- C#编程大幅提高OUTLOOK的邮件搜索能力!

简介: 原文:[原创] - C#编程大幅提高OUTLOOK的邮件搜索能力! 使用OUTLOOK, 你有没有遇到过上图的问题? 多达18419封邮件! 太多了, 每次想找一个邮件都非常耗时, 想办法解决这个问题成了一件非常紧迫的事情.
原文: [原创] - C#编程大幅提高OUTLOOK的邮件搜索能力!

使用OUTLOOK, 你有没有遇到过上图的问题? 多达18419封邮件! 太多了, 每次想找一个邮件都非常耗时, 想办法解决这个问题成了一件非常紧迫的事情. 利用MS Search当然可以, 但是它太heavy了, 而且不支持如逻辑搜索表达式等复杂查找功能, 怎么办? 幸运的是我有WEBUS2.0 SDK, 于是我决定自己开发一个名为Outlook Searcher (Outlook搜索精灵) 的小工具. 

Outlook搜索精灵主要包含两个功能:

1. 读取Outlook中的邮件信息并创建全文索引;

2. 提供搜索功能, 支持各种复杂的逻辑表达式.

先看看如何读取Outlook:

引用COM组件:

我这里引用的是9.4版本. 对应Outlook2010. 然后添加访问Outlook的代码:

using Outlook = Microsoft.Office.Interop.Outlook;

...

Outlook.Application OutlookApp;
Outlook.NameSpace OutlookNS;
Outlook.MAPIFolder Inbox;
Outlook.MAPIFolder Sentbox;

...

void InitOutlookApp()
{
    if (OutlookApp == null)
    {
        OutlookApp = new Outlook.Application();
        OutlookNS = OutlookApp.GetNamespace("MAPI");
        Inbox = OutlookNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); //获取默认的收件箱
        Sentbox = OutlookNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail); //获取默认的已发邮件
    }
}

Outlook以Folder的方式来管理收件箱, 发件箱, 已发邮件等. 一般情况下, 我们接收的邮件都在"收件箱"中, 发出的邮件都在"已发邮件"中, 因此我们从这两个文件夹中获取邮件信息. 为了更加方便使用, 我创建了一个MailInfo类型来存放需要索引的邮件内容:

public class MailInfo
{
    public string EntryId { get; set; }
    public string Folder { get; set; }
    public string From { get; set; }
    public string Subject { get; set; }
    public string ConversationId { get; set; }
    public string Body { get; set; }
    public string To { get; set; }
    public Document ToDoc()
    {
        var doc = new Document();
        doc.Fields.Add(new Field("EntryId", this.EntryId, Webus.Documents.FieldAttributes.None));
        doc.Fields.Add(new Field("Folder", this.Folder, Webus.Documents.FieldAttributes.Index));
        doc.Fields.Add(new Field("From", this.From, Webus.Documents.FieldAttributes.Index));
        doc.Fields.Add(new Field("Subject", this.Subject, Webus.Documents.FieldAttributes.AnalyseIndex));
        doc.Fields.Add(new Field("ConversationId", this.ConversationId, Webus.Documents.FieldAttributes.Index));
        doc.Fields.Add(new Field("Body", this.Body, Webus.Documents.FieldAttributes.AnalyseIndex));
        doc.Fields.Add(new Field("To", this.To, Webus.Documents.FieldAttributes.Index));
        return doc;
    }
    public MailInfo()
    {

    }
    public MailInfo(Document doc)
    {
        this.EntryId = doc.GetField("EntryId").Value.ToString();
        this.Folder = doc.GetField("Folder").Value.ToString();
        this.From = doc.GetField("From").Value.ToString();
        this.Subject = doc.GetField("Subject").Value.ToString();
        this.ConversationId = doc.GetField("ConversationId").Value.ToString();
        this.Body = doc.GetField("Body").Value.ToString();
        this.To = doc.GetField("To").Value.ToString();
    }
}

它还兼具了Mapping的功能, 能够在MailInfo和Webus.Document之间进行转换. 并且为每个字段都设定了索引选项. 现在一切就绪, 只欠东风了. 废话少说, 直接上代码:

先创建索引对象:

IIndexer IndexAccessor = null;
...
private void frmOutlookSearcher_Load(object sender, EventArgs e)
{
    ...
    this.IndexAccessor = new IndexManager(new MailAnalyzer()); //用MailAnalyzer作为分析器
    this.IndexAccessor.MaxIndexSize = int.MaxValue; //索引大小无限制
    this.IndexAccessor.MinIndexSize = int.MaxValue; //索引大小无限制
    this.IndexAccessor.MergeFactor = int.MaxValue; //不做merge
    ...
}
...
private void IndexProc()
{        
    IndexAccessor.OpenOrNew(AppDomain.CurrentDomain.BaseDirectory + @"Index"); //索引数据放在运行目录的"Index"文件夹里面
    ...
    //读取outlook, 添加文档到索引
    ...
}

再循环读取邮件并添加索引文档:

while(...)
{
    //先读取inbox
    for (; InboxIndx <= Inbox.Items.Count; InboxIndx++)
    {
        ...
        this.InitOutlookApp();
        var item = Inbox.Items[InboxIndx];
        if (item is Outlook.MailItem) //注意, 并非每个inbox的item都是mailItem, 因此要做个类型检查, 否则程序会挂起, 死在那儿.
        {
            Outlook.MailItem mailItem = item as Outlook.MailItem;
            var mailInfo = new MailInfo()
            {
                EntryId = string.IsNullOrEmpty(mailItem.EntryID) ? string.Empty : mailItem.EntryID,
                From = string.IsNullOrEmpty(mailItem.SenderEmailAddress) ? string.Empty : mailItem.SenderEmailAddress,
                ConversationId = string.IsNullOrEmpty(mailItem.ConversationID) ? string.Empty : mailItem.ConversationID,
                Subject = string.IsNullOrEmpty(mailItem.Subject) ? string.Empty : mailItem.Subject,
                Body = string.IsNullOrEmpty(mailItem.HTMLBody) ? string.Empty : mailItem.HTMLBody,
                Folder = string.IsNullOrEmpty(Inbox.Name) ? string.Empty : Inbox.Name,
                To = string.IsNullOrEmpty(mailItem.To) ? string.Empty : mailItem.To
            };
            IndexAccessor.Add(mailInfo.ToDoc()); //添加文档到索引
        }
        ...
    }
    ...
    //再读取sentbox
    for (; SentboxIndex <= Sentbox.Items.Count; SentboxIndex++)
    { ... }
}

最后将IndexProc放到后台线程中运行来提高用户体验:

private void frmOutlookSearcher_Load(object sender, EventArgs e)
{
    ...
    this.IndexAccessor = new IndexManager(new MailAnalyzer()); //用MailAnalyzer作为分析器
    this.IndexAccessor.MaxIndexSize = int.MaxValue; //索引大小无限制
    this.IndexAccessor.MinIndexSize = int.MaxValue; //索引大小无限制
    this.IndexAccessor.MergeFactor = int.MaxValue; //不做merge
    ...
    IndexingTask = Task.Factory.StartNew(this.IndexProc); //在后台线程编制索引
}

OK, 大功告成! Outlook搜索精灵支持如下搜索字段:

字段 类型 描述
Subject string 邮件标题
Body string 邮件正文, HTML格式
Folder string 邮件所属目录, 比如"收件箱", "已发邮件"等
From string 发件人
To string 收件人
ConversationId string 会话ID

 

 

 

 

 

 

 

默认情况下, Outlook搜索精灵会使用

Subject="{0}" OR Body="{0}"

进行搜索, {0}会被自动替换成输入的关键词. 但是如果我们输入的本身就是一个搜索表达式, 那么Outlook搜索精灵会自动切换成高级搜索模式, 用用户输入的表达式进行搜索.

列举几个高级搜索的例子:

//1. 搜索标题含有"张三"并且正文含有"朋友聚餐"的邮件:
Subject="张三" & Body="朋友聚餐"
//2. 在已发邮件中搜索标题中含有"张三"的邮件:
Folder="[已发邮件]" AND Subject="张三"
//3. 搜索标题包含"Hotfix"的邮件: (hotfix和hotfixing都会被搜索到)
Subject WILDCARD "hotfix"

这只是部分例子, 有了WEBUS2.0 SDK的支持, Outlook搜索精灵可以轻松实现7种不同类型的搜索, 并且支持复杂的逻辑搜索表达式, 具体请看 WEBUS2.0 In Action - 搜索操作指南 - (2).

为了让Outlook搜索精灵根据体贴好用, 我还设计了一些小功能, 比如Outlook连接中断自动重连, 最小化到托盘等. enjoy吧!

下载程序 | 下载源代码

 相关信息及WEBUS2.0 SDK下载:继续我的代码,分享我的快乐 - WEBUS2.0

目录
相关文章
|
1月前
|
C#
24. C# 编程:用户设定敌人初始血值的实现
24. C# 编程:用户设定敌人初始血值的实现
19 0
|
2月前
|
SQL 数据库连接 应用服务中间件
C#WinForm基础编程(三)
C#WinForm基础编程
73 0
|
2月前
C#WinForm基础编程(二)
C#WinForm基础编程
55 0
|
2月前
|
C# 数据安全/隐私保护
C#WinForm基础编程(一)
C#WinForm基础编程
60 0
|
4月前
|
数据采集 前端开发 C#
C#编程艺术:Fizzler库助您高效爬取www.twitter.com音频
Twitter是全球最大的社交媒体平台之一,包含丰富的音频资源。用户可以在Twitter上发布、转发、评论和收听各种音频内容,如音乐、播客、新闻、故事等,直接从Twitter抓取音频数据并非易事,尤其是在考虑到可能的封锁和反爬虫机制。Twitter会对频繁访问的IP地址进行限制或封禁,以防止恶意爬虫的行为。因此,我们需要使用一些技术手段来规避这些障碍,确保稳定而高效的数据访问。
C#编程艺术:Fizzler库助您高效爬取www.twitter.com音频
|
3月前
|
程序员 C#
深入理解 C# 编程:枚举、文件处理、异常处理和数字相加
枚举是一个特殊的“类”,表示一组常量(不可更改/只读变量)。 要创建枚举,请使用 enum 关键字(而不是 class 或 interface),并用逗号分隔枚举项:
38 0
|
2天前
|
存储 安全 网络安全
C#编程的安全性与加密技术
【4月更文挑战第21天】C#在.NET框架支持下,以其面向对象和高级特性成为安全软件开发的利器。本文探讨C#在安全加密领域的应用,包括使用System.Security.Cryptography库实现加密算法,利用SSL/TLS保障网络传输安全,进行身份验证,并强调编写安全代码的重要性。实际案例涵盖在线支付、企业应用和文件加密,展示了C#在应对安全挑战的同时,不断拓展其在该领域的潜力和未来前景。
|
2天前
|
程序员 C#
C#编程中的面向对象编程思想
【4月更文挑战第21天】本文探讨了C#中的面向对象编程,包括类、对象、封装、继承和多态。类是对象的抽象,定义属性和行为;对象是类的实例。封装隐藏内部细节,只暴露必要接口。继承允许类复用和扩展属性与行为,而多态使不同类的对象能通过相同接口调用方法。C#通过访问修饰符实现封装,使用虚方法和抽象方法实现多态。理解并应用这些概念,能提升代码的清晰度和可扩展性,助你成为更好的C#程序员。
|
3天前
|
IDE 程序员 C#
C#编程入门:从零开始的旅程
【4月更文挑战第20天】本文引导初学者入门C#编程,从环境搭建开始,推荐使用Visual Studio Community版作为IDE。接着,通过编写&quot;Hello, World!&quot;程序,介绍基本语法,包括数据类型、运算符和表达式。文章还涉及控制结构、函数和方法,以及面向对象编程概念。通过学习,读者将对C#有初步了解,并激发进一步探索编程世界的兴趣。
|
3天前
|
开发框架 .NET Java
探索 C#编程的奥秘与魅力
【4月更文挑战第20天】C#是微软开发的现代、面向对象的编程语言,以其简洁语法、强大功能和跨平台支持脱颖而出。它支持自动垃圾回收、泛型、委托、LINQ,并广泛应用于桌面、Web、移动和游戏开发。C#拥有活跃的开发者社区和丰富的资源,是Unity游戏开发的首选语言。随着.NET Core,C#可在多个操作系统上运行,持续创新,未来发展潜力巨大。