【问题标题】:Forward email based on part of a subject line根据部分主题行转发电子邮件
【发布时间】:2020-03-28 13:57:48
【问题描述】:

有没有办法在收件箱中搜索电子邮件主题行的一部分,然后将搜索结果转发到另一个电子邮件地址?

示例:
COMPLETE 电子邮件进入收件箱,电子邮件的主题行是“This is the subject COMPLETE”。我希望将主题行中带有“主题”的任何电子邮件转发到不同的电子邮件地址。

编辑:为了澄清,宏应该在主题行中搜索 COMPLETE 左侧的字母和数字的组合,长度始终为 15 个字符。

此外,当 COMPLETE 电子邮件进入收件箱时不需要触发宏(可以手动触发)。它需要将每封完整的电子邮件视为一个单独的“工作”,以重复搜索并转发每封主题中包含完整的电子邮件。

【问题讨论】:

  • 是的,有可能,但有多种方法可供您选择。
  • 您可以编写一个每天运行一次的宏,例如,循环在主题中搜索“COMPLETE”,提取 15 个字符的代码,搜索具有相同代码的其他电子邮件并进行处理找到的所有电子邮件。循环将继续,直到找不到主题包含“COMPLETE”的电子邮件。如果您选择此方法,则必须将电子邮件移至“已处理”文件夹或将其删除。如果不这样做,您将在每次运行宏时处理相同的电子邮件。
  • 替代方案,您可以有一个规则,当一封包含“COMPLETE”主题的电子邮件到达时调用宏。这个宏不会循环;它只会提取、搜索和处理一次。使用这种方法,您不必移动或删除电子邮件(尽管您可以),并且电子邮件将被立即处理,而不是每天一次。
  • 我说的是“处理”,你说的是“转发到另一封电子邮件”。我假设您的意思是另一个电子邮件地址。你确定你的意思是“前进”?通常,根据此类要求,电子邮件会被移至共享邮箱进行归档。
  • 谢谢托尼。我认为最好在触发后循环运行,是否可以让宏在发送后移动电子邮件?是的,它需要转发,因为电子邮件已经在共享收件箱中,需要发送和移动

标签: vba outlook


【解决方案1】:

我会尝试让您开始,但只有您可以调试任何代码,因为只有您拥有要转发的电子邮件。我创建了一些符合我对您的电子邮件理解的电子邮件,但我不能确定我是否完全正确。

我不知道你对 VBA 了解多少。一般来说,一旦你知道有一个陈述存在,就很容易在网上搜索解释。所以我将集中解释我的代码在做什么。

对于宏的第一阶段,您需要收集以下信息:

abcdefghijklmno  Email1  Email2  Email3 . . .
bcdefghijklmnop  Email4  Email5 . . .

其中“abcdefghijklmno”和“bcdefghijklmnop”是“工作”的代码,Email1 到 Email5 是主题包含代码的电子邮件。

对于宏,文件夹(例如收件箱)是一个集合。有不同的方法可以识别特定的电子邮件,但我认为最方便的方法是通过它在集合中的位置或索引。添加到文件夹的第一封电子邮件的索引为 1,第二封电子邮件的索引为 2,依此类推。如果您了解数组,这似乎很熟悉。不同之处在于,对于集合,您可以从集合中删除现有项目或在集合中间添加新项目。假设,我有一个包含项目 A、B、C、E 和 F 的集合,它们的索引为 1 到 5。我现在在项目 C 和 E 之间添加项目 D。项目 A 到 C 仍然是项目 1 到 3。但 D 是现在第 4 项,E 已成为第 5 项,F 已成为第 6 项。当删除一个项目时,您会遇到相反的情况,而集合中更靠后的项目的索引号会减少。这可能很奇怪,但我相信当它变得重要时会变得更加清晰。

所以我们需要创建的是:

abcdefghijklmno  25  34  70 . . .
bcdefghijklmnop  29  123 . . .

Option Explicit 之后,你可以查到,第一条语句是Type tFamily。 VBA 带有多种数据类型,例如:Long、Double、String 和 Boolean。有时这些本身还不够,我们需要将它们组合成 VBA 所称的用户类型和大多数其他语言的调用结构。你可能听说过类。类比用户类型更上一层楼,我们不需要它们的额外功能或额外的复杂性。

所以我写了:

Type tFamily
  Code As String
  Members As Collection
End Type

在这里,我将 String 和 Collection 组合成一个更大的类型,我将其命名为 tFamily。 “t”是我的标准,因为我经常难以为我的类型和变量考虑不同的名称。这种类型与我上面描述的数据相匹配。我已将所有具有相同代码的电子邮件称为家庭。在一个家庭中,我有一个字符串来保存代码和一个集合来保存所有索引。

在我的代码中,我定义了一系列家庭:

  Dim Families() As tFamily

我将在这里保存有关电子邮件系列的所有信息。

下一个重要的声明是:

  Set FldrInbox = Session.Folders("xxx").Folders("Inbox")

您需要将“xxx”替换为共享邮箱的名称。

第一个代码块,标题为识别'COMPLETE'电子邮件并在InxsItemComplete中记录它们的索引扫描收件箱中的所有电子邮件并记录每封电子邮件的索引,主题以“COMPLETE”结尾.对于上面的示例数据,最后,InxsItemComplete 将包含 123 和 70。

下一条语句是ReDim Families(1 To InxsItemComplete.Count)InxsItemComplete.Count 是完整家庭的数量。该语句大小数组Families,因此它可以容纳这个数量的家庭。集合中可以有集合,但数组中的集合更简单。

下一个块从每个“COMPLETE”中提取代码并将其和“COMPLETE”电子邮件的索引存储在Families 中。该代码假定电子邮件主题类似于:

xxxxxxxxxx abcdefghijklmno spaces COMPLETE

代码将PosCodeEnd 设置为指向“COMPLETE”之前。它会进行备份,直到找到一个非空格,然后提取前 15 个字符。然后此代码存储在Families(InxF).Code 中。邮件索引添加到Families(InxF).Members

下一个块再次扫描收件箱中的所有电子邮件。这次它会查找主题包含代码但不以“COMPLETE”结尾的电子邮件。它将这些电子邮件的索引添加到Families(InxF).Members。这些索引被添加,因此它们是升序的。当我添加转发电子邮件的宏的下一个阶段时,我将解释为什么这个顺序很重要。

第 1 阶段到此结束。转发电子邮件所需的所有数据均已收集完毕。剩余的代码块将数据输出到即时窗口,以便对其进行检查。使用我的测试电子邮件,该输出是:

abcdefghijklmno
  122 06/10/2019 13:28:38 Introductory text aaa abcdefghijklmno Progress
  124 06/10/2019 13:27:35 Introductory text ccccc  abcdefghijklmno Progress
  126 06/10/2019 13:26:05 Introductory text ccccc  abcdefghijklmno  Progress
  127 06/10/2019 13:24:54 Introductory text aaa abcdefghijklmno  COMPLETE
zyxwvutsrqponml
  121 06/10/2019 13:29:10 Introductory text bbbbbb  zyxwvutsrqponml COMPLETE
  123 06/10/2019 13:28:00 Introductory text bbbbbb  zyxwvutsrqponml   Progress
  125 06/10/2019 13:26:38 Introductory text aaa zyxwvutsrqponml  Progress

这个数据的重要部分是:

abcdefghijklmno
  122
  124
  126
  127
zyxwvutsrqponml
  121
  123
  125

即代码和索引是记录的数据。收到的时间和主题是为了帮助您识别引用的电子邮件。

您需要运行此宏并检查以下输出:

  • 已识别出每封主题以“COMPLETE”结尾的电子邮件。
  • 代码已正确提取。
  • 已找到并记录每封包含代码的电子邮件。
  • 每个代码的索引按升序排列。

如有必要,请回来提出问题。但是,请记住,我看不到您的电子邮件,因此我对调试的帮助是有限的。确认诊断输出正确后,我将添加第 2 阶段的代码。

Option Explicit
Type tFamily
  Code As String
  Members As Collection
End Type
Sub FindAndForwardCompleteConversations()

  Dim Families() As tFamily
  Dim FldrInbox As Folder
  Dim InxItemCrnt As Long
  Dim InxF As Long          ' Index into Families and InxsItemComplete
  Dim InxM As Long          ' Index into members of current family
  Dim InxsItemComplete As New Collection
  Dim Placed As Boolean
  Dim PosCodeEnd As Long
  Dim Subject As String

  Set FldrInbox = Session.Folders("xxx").Folders("Inbox")

  ' Identify the 'COMPLETE' emails and record their indices
  For InxItemCrnt = FldrInbox.Items.Count To 1 Step -1
    With FldrInbox.Items.Item(InxItemCrnt)
      If .Class = olMail Then
        If Right$(.Subject, 8) = "COMPLETE" Then
          InxsItemComplete.Add InxItemCrnt
        End If
      End If
    End With
  Next

  ReDim Families(1 To InxsItemComplete.Count)

  ' Extract code from each "COMPLETE" emails and start families with 'COMPLETE' email
  For InxF = 1 To InxsItemComplete.Count
    Subject = FldrInbox.Items.Item(InxsItemComplete(InxF)).Subject
    PosCodeEnd = Len(Subject) - 8 ' Position to space before COMPLETE
    ' Position to first non-space character before COMPLETE
    Do While Mid$(Subject, PosCodeEnd, 1) = " "
      PosCodeEnd = PosCodeEnd - 1
    Loop
    Families(InxF).Code = Mid$(Subject, PosCodeEnd - 14, 15)
    Set Families(InxF).Members = New Collection
    Families(InxF).Members.Add InxsItemComplete(InxF)
  Next

  Set InxsItemComplete = Nothing   ' Release memory of collection which is no longer needed

  ' Identify emails containing the same code as the 'COMPLETE' emails
  ' and add to the appropriate Family
  For InxItemCrnt = FldrInbox.Items.Count To 1 Step -1
    With FldrInbox.Items.Item(InxItemCrnt)
      If .Class = olMail Then
        Placed = False
        For InxF = 1 To UBound(Families)
          If Right$(.Subject, 8) <> "COMPLETE" And _
             InStr(1, .Subject, Families(InxF).Code) <> 0 Then
            ' Add InxItemCrnt to collection of members for this family
            ' so that indices are in ascending sequence
            For InxM = 1 To Families(InxF).Members.Count
              If InxItemCrnt < Families(InxF).Members(InxM) Then
                Families(InxF).Members.Add Item:=InxItemCrnt, Before:=InxM
                Placed = True
                Exit For
              End If
            Next
            If Not Placed Then
              Families(InxF).Members.Add Item:=InxItemCrnt
              Placed = True
            End If
          End If
          If Placed Then
            ' Email added to current family so not need to check other families
            Exit For
          End If
        Next
      End If
    End With
  Next

  ' Output collected information
  For InxF = 1 To UBound(Families)
    Debug.Print Families(InxF).Code
    For InxM = 1 To Families(InxF).Members.Count
      InxItemCrnt = Families(InxF).Members(InxM)
      With FldrInbox.Items.Item(InxItemCrnt)
        Debug.Print "  " & InxItemCrnt & " " & .ReceivedTime & " " & .Subject
      End With
    Next
  Next

End Sub

【讨论】:

  • 您好托尼,非常感谢您的帮助,对于之前没有回复我深表歉意。我被卷入了一个不同的项目,但最终能够回到这个项目。您上面的代码运行良好。对于第二阶段,我假设我现在需要通过电子邮件将每个“家庭”发送到指定地址,为了进行测试,我将使用自己的电子邮件。请让我知道继续执行第 2 阶段代码需要什么。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 2018-04-16
  • 1970-01-01
相关资源
最近更新 更多