介绍

以编程方式解析电子邮件消息是归档工具、合规流水线和迁移实用程序的常见需求。Outlook MSG 文件使用复合文件二进制(CFB)容器格式以及 MAPI 属性流,而 EML 文件遵循 MIME 标准。这两种格式都需要仔细处理编码、折叠的标题以及嵌套的附件。

Aspose.Email FOSS for .NET 是一个免费、MIT 许可证的 C# 库,提供完整的读写 API,用于 MSG 和 EML 消息。它面向 .NET 8.0+,且不依赖 Microsoft Outlook 或任何本机 COM 互操作层。该库以 aspose.email.foss NuGet 包的形式提供。

本文将逐步介绍该库中包含的消息解析功能,从磁盘加载文件到提取各个 MAPI 属性以及在不同格式之间转换。


包含内容

加载 MSG 文件

MapiMessage 类是处理 Outlook MSG 文件的主要入口点。您可以从文件路径或流加载消息,并可选择使用 strict-validation 标志,以显示文件中发现的任何结构性问题。

// Load an MSG file from disk
var message = MapiMessage.FromFile("meeting-invite.msg");

Console.WriteLine($"Subject: {message.Subject}");
Console.WriteLine($"From: {message.SenderName} <{message.SenderEmailAddress}>");
Console.WriteLine($"Date: {message.MessageDeliveryTime}");
Console.WriteLine($"Recipients: {message.Recipients.Count}");
Console.WriteLine($"Attachments: {message.Attachments.Count}");

返回的 MapiMessage 为常用字段公开了类型化属性,包括 SubjectBodyHtmlBodySenderNameSenderEmailAddressInternetMessageIdMessageDeliveryTime

加载 EML 消息

EML 文件使用 MIME 格式。MapiMessage.LoadFromEml 接受文件路径、Streambyte[],并返回相同的 MapiMessage 对象,因此无论源格式如何,都可以使用统一的 API。

// Load from a file path
var fromFile = MapiMessage.LoadFromEml("newsletter.eml");

// Load from a stream
using var stream = File.OpenRead("newsletter.eml");
var fromStream = MapiMessage.LoadFromEml(stream);

Console.WriteLine($"Subject: {fromStream.Subject}");
Console.WriteLine($"Body: {fromStream.Body?.Trim()}");

解析器能够处理折叠的标题、Base64 和 quoted-printable 传输编码,以及多收件人的 To/Cc 字段。

处理收件人和附件

加载消息后,收件人和附件作为强类型集合可用。每个 MapiRecipient 包含 EmailAddressDisplayNameRecipientType 字段。每个 MapiAttachment 提供 FilenameDataMimeTypeContentId

var message = MapiMessage.FromFile("report.msg");

foreach (var recipient in message.Recipients)
{
    Console.WriteLine($"  {recipient.DisplayName} <{recipient.EmailAddress}> (type={recipient.RecipientType})");
}

foreach (var attachment in message.Attachments)
{
    Console.WriteLine($"  {attachment.Filename} ({attachment.MimeType}, {attachment.Data.Length} bytes)");
    File.WriteAllBytes(attachment.Filename!, attachment.Data);
}

也支持嵌入的消息附件。当 MapiAttachment.IsEmbeddedMessagetrue 时,EmbeddedMessage 属性返回一个嵌套的 MapiMessage,可递归检查。

访问 MAPI 属性

对于高级场景,每个消息、收件人和附件都公开一个 Properties 集合,类型为 MapiPropertyCollection。您可以通过属性 ID 和类型代码读取、添加和删除单个 MAPI 属性。

var message = MapiMessage.FromFile("custom-props.msg");

// Iterate all properties on the message
foreach (var prop in message.Properties.IterProperties())
{
    Console.WriteLine($"Tag: 0x{prop.PropertyTag:X8}, Value: {prop.Value}");
}

// Read a specific property
var subject = message.Properties.Get(
    (ushort)CommonMessagePropertyId.Subject,
    (ushort)PropertyTypeCode.PtypString);

CommonMessagePropertyId 枚举定义了核心消息语义、正文字段、传输标头和附件元数据的知名 MAPI 属性标识符。

在 MSG 与 EML 之间转换

解析后的消息可以重新保存为任意一种格式。Save() 写入 MSG 字节,而 SaveToEml() 生成 MIME 输出。这使得格式转换变得直接。

// Load an EML and save as MSG
var message = MapiMessage.LoadFromEml("incoming.eml");
message.Save("converted.msg");

// Load an MSG and save as EML
var msg = MapiMessage.FromFile("outgoing.msg");
msg.SaveToEml("exported.eml");

这两种方法同样接受一个 Stream 参数,以实现内存中的处理,无需触及文件系统。


快速入门

从 NuGet 安装该包:

dotnet add package Aspose.Email.FOSS

然后解析你的第一条消息:

using Aspose.Email.Foss.Msg;

// Load an MSG file
var message = MapiMessage.FromFile("sample.msg");

Console.WriteLine($"Subject:     {message.Subject}");
Console.WriteLine($"From:        {message.SenderName} <{message.SenderEmailAddress}>");
Console.WriteLine($"Date:        {message.MessageDeliveryTime}");
Console.WriteLine($"Body length: {message.Body?.Length ?? 0} chars");

// List attachments
foreach (var att in message.Attachments)
    Console.WriteLine($"  Attachment: {att.Filename} ({att.Data.Length} bytes)");

// Convert to EML
message.SaveToEml("sample.eml");
Console.WriteLine("Saved as EML.");

支持的格式

格式扩展名读取写入
Outlook MSG.msg
MIME (EML).eml
复合文件二进制.cfb

开源与许可

Aspose.Email FOSS for .NET 在 MIT 许可证下发布。完整源码可在 GitHub 的 aspose-email-foss/Aspose.Email-FOSS-for-.Net 获取。欢迎贡献、提交问题和 pull requests。


入门指南

相关资源