解析Outlook邮件文件(.msg)的技巧

在处理电子邮件时,经常需要解析Outlook生成的邮件文件(.msg)。本文将介绍如何读取邮件的基本属性、附件以及嵌套消息。将使用C#语言来实现这一过程。

使用代码

代码的使用非常简单。首先,需要创建一个OutlookStorage.Message类的实例,并向其传递一个.msg文件的路径或包含IStorage的Stream。Stream构造函数的提供使得其可以轻松地与Outlook拖放代码集成,这在另一个示例应用中有所展示。

以下是创建Outlook消息并显示其内容的示例代码:

private static void main() { // 从文件创建新的Outlook消息 OutlookStorage.Message outlookMsg = new OutlookStorage.Message( @"C:\test.msg" ); DisplayMessage(outlookMsg); } private static void DisplayMessage(OutlookStorage.Message outlookMsg) { Console.WriteLine( "Subject: {0}", outlookMsg.Subject ); Console.WriteLine( "Body: {0}", outlookMsg.BodyText ); Console.WriteLine( "{0} Recipients", outlookMsg.Recipients.Count ); foreach (OutlookStorage.Recipient recip in outlookMsg.Recipients) { Console.WriteLine( "{0}:{1}", recip.Type, recip.Email ); } Console.WriteLine( "{0} Attachments", outlookMsg.Attachments.Count ); foreach (OutlookStorage.Attachment attach in outlookMsg.Attachments) { Console.WriteLine( "{0}, {1}b", attach.Filename, attach.Data.Length ); } Console.WriteLine( "{0} Messages", outlookMsg.Messages.Count ); foreach (OutlookStorage.Message subMessage in outlookMsg.Messages) { DisplayMessage(subMessage); } }

接下来,将展示如何将消息及其所有附件保存到文件系统中。

private static void main() { // 从文件创建新的Outlook消息 OutlookStorage.Message outlookMsg = new OutlookStorage.Message( @"C:\test.msg" ); } private static void SaveMessage(OutlookStorage.Message outlookMsg) { outlookMsg.Save(outlookMsg.Subject.Replace( ":", "" )); foreach (OutlookStorage.Attachment attach in outlookMsg.Attachments) { byte[] attachBytes = attach.Data; FileStream attachStream = File.Create(attach.Filename); attachStream.Write(attachBytes, 0, attachBytes.Length); attachStream.Close(); } foreach (OutlookStorage.Message subMessage in outlookMsg.Messages) { SaveMessage(subMessage); } }

理解代码

要读取Outlook生成的.msg文件,需要理解两个概念。首先,.msg文件在逻辑上是一个MAPI对象,包含MAPI属性;其次,物理上MAPI对象及其属性存储在IStorage中。微软提供了MAPI属性映射到IStorage的规范,这里将重点讨论在保存子消息时遇到的一些特殊情况。

从父消息中保存子消息需要注意几个问题。属性流头部需要填充,并且需要将名称到ID映射存储复制到子消息存储中。

MAPI属性值可以存储在子存储、子流中,或者在固定大小值(如整数)的情况下,存储在特殊的子流——属性流中。属性流由一个可变长度的头部和一个16字节对的数组组成,其中第一个8字节包含属性标识符,第二个8字节包含属性值。

需要注意的是可变长度头部。对于附件或收件人存储,它是8字节;对于顶级消息,它是32字节;对于子消息,它是24字节。这意味着,如果想提取子消息并保存它而不包含其父消息,需要在头部的末尾填充8个空字节。

保存子消息的另一个问题是名称到ID映射存储,它只存在于顶级消息中,但包含整个树的映射。因此,在保存子消息时,需要在保存之前将其复制到子消息中,以使其有效。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485