在Outlook中用VBA进行邮件过滤

微软出的东西总会有一些脑残的设计。Outlook的邮件过滤规则,我倒腾了半天都没整明白。最终决定用VBA脚本来实现邮件过滤。

使用VBA处理新邮件,一般有三种方式,各有利弊:

  1. 在邮件规则中调用VBA脚本
    如果一次收取大量的邮件,可能会漏处理一些邮件。
    可能会出现VbaProject.otm被损坏的情况。(TMD我就遇到了
  2. 使用ItemAdd事件
    当同时进入文件夹的邮件超过16个时,ItemAdd事件将不会被触发。致命啊~~
  3. 使用NewMailEx事件
    只有使用Exchange邮箱才能触发NewMailEx事件,只有Outlook处于启动状态时才能接收NewMailEx邮件。也就是说,当Outlook关闭后收到一些新邮件,再次打开Outlook收取这些邮件时,将不会触发NewMailEx事件。也很恶心啊~~

所以,基本上就只有第一种方法比较符合我的要求。
我的需求,简化一下就是:

  1. 从a@example.com发送过来的邮件,移动到folder1
  2. 发送给b@example.com邮件组的邮件,移动到folder2
  3. 发送给c@exmpla.com邮件组的邮件,移动到folder3

OK,启动Outlook,按ALT+F11进入VBA编辑器,在ThisOutlookSession模块下,添加如下的函数:
[vb]
Sub EmailFilter(item As MailItem)
' 声明变量,好处是编辑器知道变量类型之后可以进行自动提示。
Dim id As String
Dim email As Outlook.MailItem
Dim objApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Dim inbox, folderA, folderB, folderC As Outlook.Folder

' 取得收件夹和下面的三个子目录
Set objApp = Application
Set objNS = objApp.GetNamespace("MAPI")
Set inbox = objNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
Set folderA = inbox.Folders("folder1")
Set folderB = inbox.Folders("folder2")
Set folderC = inbox.Folders("folder3")

' 为了避免出现宏警告,不直接使用item,而是先取出item的EntryID,再获取MailItem对象
id = item.EntryID
Set email = Application.Session.GetItemFromID(id)
If email.SenderEmailAddress = "a@example.com" Then
email.Move folderA
Else
Let to_group_B = False
Let to_group_C = False
Dim recipent As Outlook.Recipient
For Each recipent In email.Recipients
If recipent.AddressEntry = "b@example.com" Then
to_group_B = True
ElseIf recipent.AddressEntry = "c@example.com" Then
to_group_C = True
End If
Next
If to_group_B Then
email.Move folderB
ElseIf to_group_C Then
email.Move folderC
End If
End If
End Sub
[/vb]

编写完保存之后,新建过滤规则,在处理邮件的动作上选择“运行脚本”,这样就可以看到名为Project1.ThisOutlookSession.EmailFilter的脚本了。

Visual Basic、Visual Basic for Application和VBScript

没怎么用过VB,搞不清楚Visual Basic、Visual Basic for Application和VBScript这三个东西到底什么关系,于是google了一下,看到了一个很有意思的描述:

VB和VBA本就是同宗的姐妹,只不过姐姐VB的功夫要比妹妹VBA历害些。不过姐姐只会单打独斗是女强人;妹妹却只会傍大款(例如Office)。姐姐有生育能力,是真正的女人;妹妹却不会生崽(生成.EXE),但深谙相夫之道,一番教导指挥之下可使她老公增色不少。而VBS呢,也是大户人家的女儿,不过没有VB和VBA姐妹优秀的血统,娇小玲珑干不得粗活只能指挥些自动听话的对象来干活(ActiveX Script),她乐于助人品德好不象VBA那样只认大款。VIA

在我理解,VB>VBA>VBS,VB是一种独立的编程语言,VBA则和Office系列软件结合比较紧密,VBS则在网页中有很多应用。还有篇98年的ooooold说明,也可以看看。

VbaProject.otm文件损坏
有时候要重启outlook来测试VBA代码,因为心急,就在关闭outlook之后又马上打开。因为机器比较慢,一连点了好几下。结果运行代码就提示“找不到文件”。按ALT+F11打开Visual Basic编辑器,一片空白,啥也干不了。因为outlook的vba代码默认是存在VbaProject.otm文件里的,就google了一下"VbaProject.otm missing",找到了解决方法:

在%appdata%\Microsoft\Outlook目录下删除损坏的VbaProject.otm,重启outlook,之后会自动新建一个VbaProject.otm

很显然,之前的代码都丢了,所以,及时的备份是多么的重要!另外,我这里还犯了傻,本来在地址栏里面直接填上 %appdata%\Microsoft\Outlook 就可以直接定位到VbaProject.otm所在的目录的,我却非要自己找,然后找错了。本来是目录:

C:\Users\%user%\AppData\Roaming\Microsoft\Outlook

我却进到了下面这个目录:

C:\Users\%user%\AppData\Local\Microsoft\Outlook

结果没找到VbaProject.otm。我以为是VbaProject.otm真的丢了,就从网上下了一个别人的VbaProject.otm放在这个错误的目录,发现问题依旧,不得已重装了一些office。问题还没解决,才想到我可能是找错目录了···瞎忙活了好久!

References:
Getting Started with Outlook VBA
How to process incoming messages in Microsoft Outlook

Comments