用于保存邮件的本地副本(并重命名本地副本)的宏

时间:2019-04-08 12:19:27

标签: vba outlook outlook-vba

我工作的公司手动将某些请求(按邮件发送)保存到共享驱动器,并将其重命名为:“ YYYYMMDD_Firstname_Lastname”。邮件另存为.msg

由于我们每周大约有一百个这样的东西,所以我想对此进行宏处理,以免浪费时间。

此处的文章:Outlook VBA macro for saving emails copies in a local folder说明了如何在本地保存文件,但我想作以下补充: -重命名副本,然后将其保存到共享驱动器(如果需要,可以手动) -选择需要保存到的共享路径(最好是带有三个选项的下拉菜单) -为此创建适当的用户表单

如果任何人都可以协助编写代码,或者亲自给我提供有关如何执行此操作的教程/指南,我将非常感激。

P.S。刚刚在一周前开始使用和创建宏。还是非常初学者。不管它是否回答了我的问题,任何对开发人员的良好教程的链接都将不胜感激。

谢谢大家!

按如下方式使用文章中描述的代码:

Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
    Call SaveACopy(Item)
End Sub

Sub SaveACopy(Item As Object)
    Const olMsg As Long = 3

    Dim m As MailItem
    Dim savePath As String

    If TypeName(Item) <> "MailItem" Then Exit Sub

    Set m = Item

    savePath = "c:\users\your_user_name\desktop\"  '## Modify as needed
    savePath = savePath & m.Subject & Format(Now(), "yyyy-mm-dd-hhNNss")
    savePath = savePath & ".msg"


    m.SaveAs savePath, olMsg


End Sub

更新:使用Tony Dallimore提供的宏,我已经设法确定.SenderName是我需要处理的邮件中的主要信息。现在,我需要的是用下划线替换输出中的空格,并在其前面添加反日期以获取我的文件名。

感谢Tony Dallimore对该项目的持续协助。

由于回首我的原始问题似乎有些困惑,因此我将尝试澄清:

我每周大约收到100封邮件,通知我们某些用户请求的批准。 公司政策是在处理请求之前,将这些邮件另存为.msg在用于管理的共享驱动器上。这些消息的文件名必须是这样的: “ YYYYMMDD_FIRSTNAME_LASTNAME.msg”(其中YYYY是年份,MM是月份,DD是我们收到这些邮件的日期)

我们获得了这三种邮件的三种主要“类型”,分别保存在不同的位置,但分别使用相同的文件名。

我需要的是一个宏或一组宏,它们可以通过按一下按钮或使用最少的单击/手动输入将这些邮件以正确的格式保存在正确的网络驱动器中。

我决定使用.SenderName和.Senton,因为这些似乎可以满足我的大部分需求。

2 个答案:

答案 0 :(得分:0)

这不是您问题的直接答案。我希望这项调查能够提供答案所需的信息。

您说“……邮件是系统自动生成的……”。这可以解释为什么我不完全理解您的代码为何起作用。在提供一些背景知识之后,我将解释我的困惑。

有四种不同的方法可以选择MailItem进行处理:

  1. 用户可以选择一封或多封电子邮件,然后调用一个宏来处理所选的MailItem。 (请注意,这是给用户的电子邮件,但给宏的MailItem。)
  2. 宏可以读取或读取MailItem的文件夹,并查看属性以确定要处理的属性。 SortFilter可用于更快地定位感兴趣的MailItem
  3. 您可以指定一条规则,该规则将在每封电子邮件到达时对其进行查看,并查看诸如主题和发件人之类的属性。如果电子邮件具有必需的属性,则可以执行许多操作。如果标准操作不够用,则可以链接宏以执行VBA宏可用的任何操作。
  4. 您可以指示Outlook在发生特定事件时调用宏。事件包括:MailItem添加到文件夹Xxxx,MailItem打开,MailItem发送,MailItem保存,MailItem关闭,MailItem回复或{ {1}}已转发。

您的代码正在使用方法4。特别是,您正在使用MailItem发送事件。您说:“……我们每周大约收到一百(电子邮件)……”。如果“ get”是正确的词,我希望添加到文件夹“收件箱”中的MailItem是适当的事件。也许您的代码有效,因为系统正在生成用户X到用户X的电子邮件。

如果这些电子邮件是系统生成的,我们不能确定设置了哪些属性以及设置了哪些值。请将下面的代码复制到Outlook模块。选择其中一封或多封电子邮件,然后运行宏CallSubForSelectedEmails。

MailItem

对于我的一封电子邮件,此例程输出:

Option Explicit
Public Sub CallSubForSelectedEmails()

  Dim Exp As Explorer
  Dim ItemCrnt As MailItem

  Set Exp = Outlook.Application.ActiveExplorer

  If Exp.Selection.Count = 0 Then
    Call MsgBox("Please select one or more emails then try again", vbOKOnly)
    Exit Sub
  Else
    For Each ItemCrnt In Exp.Selection
      If ItemCrnt.Class = olMail Then
        Call DsplSimpleProperties(ItemCrnt)
      End If
    Next
  End If

End Sub
Sub DsplSimpleProperties(ItemCrnt As Outlook.MailItem)

  Dim InxR As Long

  Debug.Print "=============================================="
  Debug.Print "  Profile: " & Session.CurrentProfileName
  Debug.Print "     User: " & Session.CurrentUser
  With ItemCrnt
    Debug.Print "  Created: " & .CreationTime
    Debug.Print " Receiver: " & .ReceivedByName
    Debug.Print " Received: " & .ReceivedTime
    For InxR = 1 To .Recipients.Count
      Debug.Print "Recipient: " & .Recipients(InxR)
    Next
    Debug.Print "   Sender: " & .Sender
    Debug.Print " SenderEA: " & .SenderEmailAddress
    Debug.Print " SenderNm: " & .SenderName
    Debug.Print "   SentOn: " & .SentOn
    Debug.Print "  Subject: " & .Subject
    Debug.Print "       To: " & .To
  End With

End Sub

注1,我既是系统用户,也是此电子邮件的收件人。这提供了两种获取我的名字和姓氏的方法。我在电子邮件地址中使用首字母缩写,但您的公司可以使用姓名。

注2:我的代码使用方法1选择要处理的电子邮件。宏CallSubForSelectedEmails为每个选定的电子邮件调用宏DsplSimpleProperties。我使用这样的代码进行所有调查和所有电子邮件处理宏的开发。这使我可以完全控制要处理的电子邮件。宏DsplSimpleProperties的调用配置文件与规则宏或事件宏的调用配置文件相同。一旦我使用方法1调试了宏,并切换到从规则或事件中进行调用,而无需进行额外的测试。我知道没有比这更容易调试电子邮件处理宏的方法了。

答案 1 :(得分:0)

同样,这不是完整答案,因为我没有完整答案的信息。

任务1:生成路径名

路径名的信息来自MailItem的{​​{1}}。对于此示例,我假设请求类型为1、2或3,它是主题的最后一个字符。

Subject

Dim PathName As String ' Generate end of subfolder name Select Case Right$(ItemCrnt.Subject,1) Case "1" PathName = "xxxx" Case "2" PathName = "yyyy" Case "3" PathName = "zzzz" Case Else ' Subject does not conform to expected format. Exit Sub End Select ' Prefix root folder name and year of subfolder name PathName = "P:\EMEA Requests\" & Year(ItemCrnt.SentOn) & "\" & PathName 是从字符串中提取指定数量的尾随字符的函数。功能Right$Left$也可用。如果主题足够复杂,我们可以考虑使用正则表达式。 Mid$是从日期中提取年份的函数。该值将是一个整数,但如果VBA用作字符串,则VBA会自动将其转换为字符串。

如果例程无法识别请求类型,则放弃Year。稍后我将讨论这个问题。

任务1;建议2:生成路径名

您说主题缺乏固定格式,仅包含原始请求中的单词。您暗示这些单词足以使人员识别请求类型。因此,请求字词可能包括“硬件”,“ h'ware”,“计算机”或“笔记本电脑”。另一个请求可能包括“软​​件”,“应用程序”或“应用程序”。这是处理这种情况的一种简单方法。如果可行,我将介绍一种更好的方法。

MailItem

您可以继续添加可能的关键字,直到您的请求者用尽其他选项为止。宏处理完简单的消息后,您无法通过按钮使用用户窗体。

任务2:生成文件名

If Instr(1, LCase(ItemCrnt.Subject), "hardware") <> 0 Then 
  PathName = "xxxx"
ElseIf Instr(1, LCase(ItemCrnt.Subject), "h'ware") <> 0 Then 
  PathName = "xxxx"
ElseIf Instr(1, LCase(ItemCrnt.Subject), "computer") <> 0 Then 
  PathName = "xxxx"
ElseIf Instr(1, LCase(ItemCrnt.Subject), "laptop") <> 0 Then 
  PathName = "xxxx"
ElseIf Instr(1, LCase(ItemCrnt.Subject), "software") <> 0 Then 
  PathName = "yyyy"
ElseIf Instr(1, LCase(ItemCrnt.Subject), "application") <> 0 Then 
  PathName = "yyyy"
ElseIf Instr(1, LCase(ItemCrnt.Subject), "app") <> 0 Then 
  PathName = "yyyy"
Else
  PathName = ""
End If

任务0:设计

在开始编码之前,您需要设计整个过程。您可以从简单的事情开始,然后在您更好地了解自己的需求时进行开发。您可以像使用Dim FileName As String FileName = Format(ItemCrnt.SentOn, "yymmdd") & " " & Replace(ItemCrnt.SenderName," ", "_") PathName一样对一些位进行编码,以便您了解需要组合在一起的位。但是,在没有计划的情况下处理复杂的事情很少会令人满意地结束。

我对您的要求的理解还不完整,但我会去做一个设计。

我会有一个规则,可以将这种类型的传入电子邮件复制到Outlook文件夹,例如“未保存的EMEA请求”。注意:这些是副本;原稿保留在收件箱中,以便按要求进行处理。我认为在规则可用的功能范围内,有一种方法可以识别这些电子邮件。

我会将所有代码都放在一个宏中,每天酌情调用一次或两次。该宏将读取文件夹“未保存的EMEA请求”。如果它可以为邮件生成路径和文件名,它将把邮件保存到所需的光盘文件夹中,并从Outlook文件夹中删除该邮件。如果无法处理邮件,它将保留在Outlook文件夹“未保存的EMEA请求”中。如果Outlook文件夹“未保存的EMEA请求”中留有消息,​​您将知道(1)宏需要增强以处理以前未遇到的消息类型,或者(2)规则需要修改,因为它复制了错误的消息类型。

我说的是“读取文件夹”而不是“读取文件夹”。您可以通过以下位置访问文件夹中的FileName:1、2、3,... Folder.Count。如果删除MailItem 2,则MailItem 3变成MailItem 2,MailItem 4变成MailItem 3,依此类推。 Folder.Count的值减少一。有时您会看到这样的问题:为什么它们的宏仅每隔MailItem处理一次。原因是他们的编码如下:

MailItem

使用上面的代码,您依次处理项目1、2、3。如果删除项目2,您将跳过原来的项目3,因为它现在是项目2。

正确的代码是:

For InxI = 1 to Folder.Count
  ' Process and delete Folder.Item(InxI)
Next

使用此代码,您依次处理项目10、9、8、7。如果删除项目9,则不必担心项目10已成为项目9,因为您现在正在处理项目8。

如果您仅阅读项目,则无需担心此问题。但是,如果要添加或删除项目,则确实需要担心。