65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的 Microsoft Outlook 2007 垃圾邮件过滤器

2010年3月15日

CPOL

2分钟阅读

viewsIcon

31323

downloadIcon

992

一个非常简单的 Outlook 垃圾邮件过滤器。

引言

你是否曾想过能否通过自己的规则来增强 Outlook 的垃圾邮件过滤器?

如果你的答案是肯定的,那么这篇文章就是为你准备的。编码的解决方案比你想象的要简单。

背景

正确的方法是从 Visual Studio 创建一个 Outlook 2007 插件。问题是,当你第一次查看预定义的 Visual Studio 模板时,它看起来太难了。

看起来是这样

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;

namespace OutlookSpamFilter
{
    public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        { 
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }

        #region VSTO

        /// <summary>
        /// [INTERNAL]
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }

        #endregion
    }
}	 

但是,如果你仔细观察,你可能会发现 "this.Application.NewMailEx"。它是本文的核心,一个用于捕获新邮件事件的 Outlook 事件。

Using the Code

一旦检测到新邮件事件,代码就非常简单了。但有两种选择:

  1. 每次收到邮件时,扫描所有收件箱文件夹(我强烈反对这种选择)
  2. 检查新邮件项目是否存在垃圾邮件条件

最简单的垃圾邮件检查条件是在典型的电子邮件文本字段中找到一个特殊的字符串,因此我们需要一个垃圾邮件字符串列表。

 SpamTokens = new string[] { "Viagra", ".ru/", "Can't view email?","SpamTest" }; 

当在电子邮件中找到像 string 这样的字符串时,这封邮件很可能是垃圾邮件。

要检查的电子邮件字段包括:

  • SenderName:发送者的姓名
  • Body:文本电子邮件正文
  • HTMLBody:HTML 正文(如果电子邮件包含 HTML 内容)
  • SenderEmailAdress:发送者的地址
  • Subject:电子邮件的主题

电子邮件过滤条件应检查列表中每个电子邮件对象。因此,我们执行检查并将邮件移动到“垃圾邮件”文件夹的操作。请注意,对于每个电子邮件对象和每个 string,我们都执行垃圾邮件检查条件(使用 "ToUpperInvariant" 以忽略大小写)。

private void CheckSpamCondition(MAPIFolder mfJunkEmail, System.Object oBoxItem)
{
	if (oBoxItem is Outlook.MailItem)
	{
		Outlook.MailItem miEmail = (Outlook.MailItem)oBoxItem;
		foreach (string SpamToken in SpamTokens)
		{
			string strSpamToken = SpamToken.ToUpperInvariant();
			if (miEmail.SenderName.ToUpperInvariant().
				Contains(strSpamToken))
			{
				miEmail.Move(mfJunkEmail);
				break;
			}
			else if (miEmail.Body.ToUpperInvariant().
				Contains(strSpamToken))
			{
				miEmail.Move(mfJunkEmail);
				break;
			}
			else if (miEmail.HTMLBody.ToUpperInvariant().
				Contains(strSpamToken))
			{
				miEmail.Move(mfJunkEmail);
				break;
			}
			else if (miEmail.SenderEmailAddress.ToUpperInvariant().
				Contains(strSpamToken))
			{
				miEmail.Move(mfJunkEmail);
				break;
			}
			else if (miEmail.Subject.ToUpperInvariant().
				Contains(strSpamToken))
			{
				miEmail.Move(mfJunkEmail);
				break;
			}
		}
	}
} 

此外,添加了一个非常简单的数据库字符串,该数据库将令牌列表保存在文件中,或在 Outlook 启动时重新加载它。

加载系统非常简单,如果文件存在则加载其内容,否则创建一个空列表。如果你设置了属性,则该值将保存在 RAM 中并保存到磁盘。

#region Token database
/// <summary>
/// Cached spam tokens
/// </summary>
string[] g_CachedSpamTokens = null;
/// <summary>
/// Tokens considered to mark mails as spam
/// </summary>
public string[] SpamTokens
{
	get
	{
		string strDbPath = TokenDatabasePath();
		if (g_CachedSpamTokens == null)
		{
			if (File.Exists(strDbPath))
			{// recover saved database
				List<string> g_SpamTokens = new List<string>();
				foreach (string strToken in 
				    File.ReadAllLines(strDbPath, Encoding.UTF8))
				{
					if (strToken != null && 
						strToken.Trim().Length > 0)
						g_SpamTokens.Add(strToken);
				}
				g_CachedSpamTokens = g_SpamTokens.ToArray();
			}
			else
			{// no saved database
				g_CachedSpamTokens = new string[0];
			}
		}

		return g_CachedSpamTokens;
	}
	set
	{
		g_CachedSpamTokens = value;
		File.WriteAllLines(TokenDatabasePath(), value, Encoding.UTF8);
	}
}
/// <summary>
/// Path to the Spam Token list database
/// </summary>
/// <returns></returns>
private static string TokenDatabasePath()
{
	return Path.Combine(Environment.GetFolderPath
	(Environment.SpecialFolder.LocalApplicationData), "OutlookSpamFilter.db");
}
#endregion	 

第一个垃圾邮件检查选项(完全扫描)(最差性能)

此选项采用 NewEmail void 事件,并对收件箱或收件箱子文件夹中的每个电子邮件项目执行完全扫描搜索。

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
	// register the new email event
	this.Application.NewMail += new ApplicationEvents_11_NewMailEventHandler
		(Application_NewMail); // (Full-scan office 2003 version)	
}
/// <summary>
/// When new email arrives (Full-scan office 2003 version)
/// </summary>
void Application_NewMail()
{
	try
	{
		MAPIFolder mfInbox = this.Application.ActiveExplorer().
		Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);

		MAPIFolder mfJunkEmail = this.Application.ActiveExplorer().
		Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderJunk);

		Queue<MAPIFolder> qInboxSubfolderIteration = new Queue<MAPIFolder>();
		qInboxSubfolderIteration.Enqueue(mfInbox);
		List<MAPIFolder> lInboxSubfolders = new List<MAPIFolder>();
		while (qInboxSubfolderIteration.Count > 0)
		{
			MAPIFolder mf = qInboxSubfolderIteration.Dequeue();
			lInboxSubfolders.Add(mf);

			foreach (MAPIFolder mf2 in mf.Folders)
				qInboxSubfolderIteration.Enqueue(mf2);
		}

		foreach (MAPIFolder mf in lInboxSubfolders)
		{
			foreach (System.Object oBoxItem in mfInbox.Items)
			{
				CheckSpamCondition(mfJunkEmail, oBoxItem);
			}
		}
	}
	catch (System.Exception ex)
	{// if something fails do not bother user
		Console.WriteLine(ex.Message);
		Console.WriteLine(ex.StackTrace);
	}
} 

第二个垃圾邮件检查选项(仅新邮件)(最佳性能)

此选项使用 NewMailEx 事件,此事件包含逗号分隔的每个新接收电子邮件的列表。因此,我们需要使用简单的逗号分隔,然后使用一个函数将 ID 转换为电子邮件项目(Application.Session.GetItemFromID)。

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
	// register the new email event
	this.Application.NewMailEx += 
		new ApplicationEvents_11_NewMailExEventHandler(Application_NewMailEx);
}

/// <summary>
/// When new mail has arrived
/// </summary>
/// <param name="EntryIDCollection">A comma-separated ID collection as string</param>
void Application_NewMailEx(string EntryIDCollection)
{
	MAPIFolder mfJunkEmail = this.Application.ActiveExplorer().
		Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderJunk);

	string[] ids = EntryIDCollection.Split(',');
	foreach (string s in ids)
	{
		object oBoxItem = Application.Session.GetItemFromID(s, Type.Missing);

		CheckSpamCondition(mfJunkEmail, oBoxItem);
	}
} 

关注点

这段代码发布出来是为了被修改。它只是一个演示。但是,如果你想使用令牌字符串列表数据库,请记住删除源代码中的 "// debug" 行。

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
	// register the new email event
	//this.Application.NewMail += new ApplicationEvents_11_NewMailEventHandler
		(Application_NewMail); // (Full-scan office 2003 version)
	this.Application.NewMailEx += new ApplicationEvents_11_NewMailExEventHandler
		(Application_NewMailEx);

	// debug
	SpamTokens = new string[] { "Viagra", ".ru/", "Can't view email?","SpamTest" };
} 

历史

  • 2010-03-14:添加了一些说明
© . All rights reserved.