管理邮件附件

在 Outlook 中处理附件

创建和保存 Outlook 消息(MSG)文件 解释了如何创建和保存消息,以及如何创建带附件的 MSG 文件。本文说明了如何使用 Aspose.Email 管理 Microsoft Outlook 附件。使用该方法可以访问消息文件中的附件并将其保存到磁盘。 MapiMessage附件 属性的重载版本。 附件 属性是类型为的集合 MapiAttachmentCollection 类。

检查附件类型(内联或常规)

内联附件和常规附件的用途不同。内联附件在视觉上集成到电子邮件中,通常是图像或媒体文件。而常规附件是附加在电子邮件上的独立文件,可能包括各种类型的文件。 MapiAttachment.IsInline 属性的 MapiAttachment 类获取指示附件是内联还是普通的值。

下面的代码示例提取并显示已加载 MapiMessage 中每个附件的信息,包括其显示名称以及是否为内联附件。

var message = MapiMessage.Load(fileName);

foreach (var attach in message.Attachments)
{
    Console.WriteLine($"{attach.DisplayName} : {attach.IsInline}");
}

检查附件类型(IsReference)

MapiAttachment 类包含了 IsReference 属性允许开发人员在消息中识别引用附件。使用下面的代码示例,您可以检查附件是否为引用附件:

foreach (var attachment in msg.Attachments)
{
    if (attachment.IsReference)
    {
        // Process reference attachment
    }
}

从 MSG 文件保存附件

从 MSG 文件保存附件:

  1. 遍历 MapiAttachmentCollection 集合并获取各个附件。
  2. 要保存附件,请调用 MapiAttachment 类的 Save() 方法。

下面的代码片段展示了如何将附件保存到本地磁盘。

// Create an instance of MapiMessage from file
MapiMessage message = MapiMessage.FromFile(dataDir + fileName);

// Iterate through the attachments collection
foreach (MapiAttachment attachment in message.Attachments)
{
    // Save the individual attachment
    attachment.Save(dataDir + attachment.FileName);
}

从 RTF 格式的 MSG 文件中提取附件

对于 RTF 格式的消息,可以使用以下代码区分并提取内联附件或以图标形式出现在消息正文中的附件。下面的代码片段展示了如何识别并提取 RTF 格式 MSG 中的嵌入式附件。


var eml = MapiMessage.Load("MSG file with RTF Formatting.msg");

foreach (var attachment in eml.Attachments)
{
    if (IsAttachmentInline(attachment))
    {
        try
        {
            SaveAttachment(attachment, Guid.NewGuid().ToString());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

static bool IsAttachmentInline(MapiAttachment attachment)
{
    foreach (var property in attachment.ObjectData.Properties.Values)
    {
        if (property.Name == "\x0003ObjInfo")
        {
            var odtPersist1 = BitConverter.ToUInt16(property.Data, 0);
            return (odtPersist1 & (1 << (7 - 1))) == 0;
        }
    }
    return false;
}

static void SaveAttachment(MapiAttachment attachment, string fileName)
{
    foreach (var property in attachment.ObjectData.Properties.Values)
    {
        if (property.Name == "Package")
        {
            using var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
            fs.Write(property.Data, 0, property.Data.Length);
        }
    }
}

获取嵌套邮件附件

嵌入的 OLE 附件也出现在 MapiMessage Attachment 类的集合。下面的代码示例解析消息文件中的嵌入式邮件附件并将其保存到磁盘。 MapiMessage FromProperties 类的静态方法可以从嵌入的附件创建新消息。下面的代码片段展示了如何获取嵌套的邮件附件。

// Create a MapiMessage object from the individual attachment
MapiMessage getAttachment = MapiMessage.FromProperties(attachment.ObjectData.Properties);

// Convert the embedded message to a MailMessage and save it to disk
MailMessage mailMessage = getAttachment.ToMailMessage(new MailConversionOptions());
mailMessage.Save(dataDir + @"NestedMailMessageAttachments_out.eml", SaveOptions.DefaultEml);

删除附件

Aspose Outlook 库提供了从 Microsoft Outlook 消息(.msg)文件中删除附件的功能:

  • 调用 RemoveAttachments() 方法。它接受消息文件的路径作为参数。该方法实现为公共静态方法,无需实例化对象。

以下代码片段展示了如何删除附件。

MapiMessage.RemoveAttachments(dataDir + "AttachmentsToRemove_out.msg");

您也可以调用 MapiMessage 类的静态方法 DestroyAttachments()。它比 RemoveAttachments() 更快,因为 RemoveAttachments() 方法会解析邮件文件。

MapiMessage.DestroyAttachments(dataDir + "AttachmentsToDestroy_out.msg");

添加 MSG 附件

Outlook 消息可以在附件中包含其他 Microsoft Outlook 消息,无论是常规还是嵌入式消息。 MapiAttachmentCollection 提供了该类的重载成员 添加 创建带有两种附件的 Outlook 邮件的方法:

  • Add(string name, byte[] data) – 从字节数组添加常规附件。
  • Add(string name, MapiMessage message) – 将另一封 Outlook 邮件作为嵌入邮件添加。

以下代码片段展示了如何向邮件添加两种类型的附件。

MapiMessage message = new MapiMessage("from@test.com", "to@test.com", "Subj", "This is a message body");

// Add a regular attachment from a byte array
message.Attachments.Add("note.txt", File.ReadAllBytes(dataDir + "note.txt"));

// Add another Outlook message as an embedded message
MapiMessage attachMsg = MapiMessage.FromFile(dataDir + "Message.msg");
message.Attachments.Add("Weekly report.msg", attachMsg);

message.Save(dataDir + "WithAttachments_out.msg");

向 MapiMessage 添加引用附件

ReferenceAttachmentOptions 该类通过将所有必要属性封装在一个对象中,简化了添加引用附件的过程。

ReferenceAttachmentOptions 参数:

  • sharedLink:由托管文件的网络服务提供的完整共享链接。
  • url:文件位置或资源 URL。
  • providerName:引用附件提供者的名称(例如 Google Drive、Dropbox)。
  • 示例:使用 ReferenceAttachmentOptions 添加引用附件
var options = new ReferenceAttachmentOptions(
    "https://drive.google.com/file/d/1HJ-M3F2qq1oRrTZ2GZhUdErJNy2CT3DF/",
    "https://drive.google.com/drive/my-drive",
    "GoogleDrive");

// Add reference attachment
msg.Attachments.Add("Document.pdf", options);

将消息嵌入为附件

下面的代码片段展示了如何将 MSG 文件附件嵌入到消息中。

MapiMessage message = new MapiMessage("from@test.com", "to@test.com", "Subj", "This is a message body");
MapiMessage attachMsg = MapiMessage.FromFile(dataDir + "Message.msg");
message.Attachments.Add("Weekly report.msg", attachMsg);
message.Save(dataDir + "WithEmbeddedMsg_out.msg");

从附件读取嵌入式消息

以下代码片段展示了如何从附件中读取嵌入式消息。

var message = MapiMessage.FromFile(fileName);
if (message.Attachments[0].ObjectData.IsOutlookMessage)
{
    var getData = message.Attachments[0].ObjectData.ToMapiMessage();
}

插入和替换附件

Aspose.Email API 提供了在父消息中按特定索引插入附件的能力,还提供了将附件内容替换为另一条消息附件的功能。

在特定位置插入附件

Aspose.Email API 提供了使用 MapiAttachmentCollection 的 Insert 方法(MapiAttachmentCollection Insert(int index, string name, MapiMessage msg))将 MSG 附件插入到父 MSG 中的功能。下面的代码片段展示了如何在特定位置插入附件。

var message = MapiMessage.FromFile(fileName);
var memoryStream = new MemoryStream();
message.Attachments[2].Save(memoryStream);
           
var getData = MapiMessage.FromStream(memoryStream);
message.Attachments.Insert(1, "new 11", getData);

替换附件内容

可以使用 Replace 方法将嵌入的附件内容替换为新内容。但无法在集合计数为 2 的情况下,向集合中插入 PR_ATTACH_NUM = 4(例如)的附件。下面的代码片段展示了如何替换附件内容。

var message = MapiMessage.FromFile(fileName);
var memoryStream = new MemoryStream();
message.Attachments[2].Save(memoryStream);
var getData = MapiMessage.FromStream(memoryStream);
message.Attachments.Replace(1, "new 1", getData);

重命名 MapiMessage 中的附件

可以编辑 MapiMessage 附件中的 DisplayName 属性值。

var msg = MapiMessage.Load(fileName);
msg.Attachments[0].DisplayName = "New display name 1";
msg.Attachments[1].DisplayName = "New display name 2";

从数字签名的消息中保存附件

Aspose.Email API 提供了获取或设置指示是否对明文签名消息进行解码的值的功能。 

从 oledata.mso 中提取嵌入的 OLE 对象

有时嵌入的 OLE 数据表现为一个 oledata.mso 附件在 MapiAttachment )结合使用,并需手动提取。这些 oledata.mso 这些文件采用 Microsoft Compound Document File(MCDF)格式,Aspose.Email 不包含对此类文件的直接支持。但可将 Aspose.Email 与其他开源库(例如 OpenMCDF以读取这些文件的内容并保存到磁盘。Aspose.Email 提供 InlineAttachmentExtractor 类用于枚举二进制数据中包含的 MSO 包, oledata.mso,随后可以将其传递给复合文件读取库进行内容提取。

当消息正文类型为 HTML(而非 RTF)且消息中包含 OLE 对象时, MapiPropertyTag.PR_ATTACH_DATA_OBJ 属性不存在。在这种情况下,OLE 对象的信息包含在 oledata.mso.

使用 Aspose.Email 和 OpenMCDF 提取内容:

  • oledata.mso 附件。
  • 对每个 OLE 项,读取复合文件。
  • 读取名为 CONTENTS.
  • 将内容保存到一个 FileStream.
// The path to the File directory
string dataDir = RunExamples.GetDataDir_Email();

MapiMessage msg = MapiMessage.FromFile(dataDir + "double.msg");
foreach (MapiAttachment mapiAttachment in msg.Attachments)
{
    if (mapiAttachment.LongFileName == "oledata.mso")
    {
        IDictionary<string, byte[]> oledata = InlineAttachmentExtractor.EnumerateMsoPackage(new MemoryStream(mapiAttachment.BinaryData));
        int index = 0;
        foreach (var oleItem in oledata)
        {
            // Using the OpenMCDF library
            CompoundFile cf = new CompoundFile(new MemoryStream(oleItem.Value));
            CFStream contents = cf.RootStorage.GetStream("CONTENTS");
            using (FileStream fs = File.OpenWrite(index + ".pdf"))
            {
                byte[] data = contents.GetData();
                fs.Write(data, 0, data.Length);
                fs.Flush();
                fs.Close();
            }
            index++;
        }
    }
}