在处理电子邮件时,经常需要解析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映射存储,它只存在于顶级消息中,但包含整个树的映射。因此,在保存子消息时,需要在保存之前将其复制到子消息中,以使其有效。