Skip to main content
 首页 » 编程设计

c#之如何使用 Mailkit 读取电子邮件正文中的内联图像

2024年02月25日38del

我给自己发了一封测试邮件,邮件正文中有一张图片。此图像不是附件,只是粘贴到电子邮件正文中。

我正在使用 MailKit 阅读这封收到的电子邮件,但找不到如何访问该图像。

我正在使用:

MimeMessage message = client.Inbox.GetMessage(uid); 

如果我使用 message.ToString(),我可以看到它在那里:

... 
Content-Disposition: inline; filename="image001.png"; size=4570; 
        creation-date="Mon, 16 Sep 2019 09:21:07 GMT"; 
        modification-date="Mon, 16 Sep 2019 09:21:07 GMT" 
Content-ID: <image001.png@01D56A4B.7CD234E0> 
Content-Transfer-Encoding: base64 
 
iVBORw0KGgoAAAANSUhEUgAAAJUAAAAlCAY... 

我假设 base64 编码的行是实际图像,但我该如何获取它?

编辑

这是我的测试代码:

    static void Main(string[] args) 
    { 
        ImapClient client = new ImapClient(); 
        client.Connect("... 
        client.Authenticate("... 
        client.Inbox.Open(FolderAccess.ReadWrite); 
        IList<UniqueId> uids = client.Inbox.Search(SearchQuery.All); 
        foreach (UniqueId uid in uids) 
        { 
            MimeMessage message = client.Inbox.GetMessage(uid); 
 
            IList<IMessageSummary> info = client.Inbox.Fetch(new[] { uid }, MessageSummaryItems.All); 
 
            foreach (MimeEntity me in message.Attachments) 
                HandleMimeEntity(me, 1); 
        } 
        client.Disconnect(true); 
    } 
 
    static void HandleMimeEntity(MimeEntity entity) 
    { 
        int i, j; 
 
        Multipart multipart = entity as Multipart; 
 
        if (multipart != null) 
        { 
            Console.WriteLine("multipart"); 
            for (i = 0; i < multipart.Count; i++) 
            { 
                Console.WriteLine(i + " - " + multipart[i].ContentType.MimeType + " (" + multipart[i].IsAttachment + ")"); 
                HandleMimeEntity(multipart[i]); 
            } 
            return; 
        } 
 
        MessagePart rfc822 = entity as MessagePart; 
 
        if (rfc822 != null) 
        { 
            MimeMessage message = rfc822.Message; 
            Console.WriteLine("mimemessage - " + message.Subject); 
 
            HandleMimeEntity(message.Body, lvl + 1); 
            return; 
        } 
 
        MimePart part = (MimePart)entity; 
        Console.WriteLine("mimepart - " + part.FileName); 
 
        // do something with the MimePart, such as save content to disk 
    } 

请您参考如下方法:

我真的,真的,真的推荐阅读 FAQ和/或 README了解 MIME 的结构,以便对此类问题的回答变得显而易见,但与此同时......

让我们从理解 MIME 是一个树结构开始,这意味着有一个根节点(可能是也可能不是叶节点),可以有分支节点(例如。multipart/mixed、multipart/alternative、multipart/related 等),还有叶节点(例如 text/plain、text/html, image/jpeg, application/octet-stream 等)。

MIME 结构的根节点是MimeMessage.Body属性(property)。

如果消息仅包含一个 text/plain MIME 实体,则 MimeMessage.Body 节点将 text/普通 MIME 实体。

在您的情况下,听起来您至少有一个 text/html 实体和一个 image/png 实体。

由于对消息的结构一无所知,我们可以得出结论,MimeMessage.Body 不是 text/html 实体,也不是 image/png 实体,因为您只能有 1 个根节点,并且 text/* 和 image/* 部分是叶节点实体,而不是分支节点实体。

这意味着 MimeMessage.Body 将是一个 multipart/*,由 Multipart 表示(或其子类)。

由于很明显您的情况下的 MimeMessage.Body 是一个 Multipart,我们可以将其转换为:

var multipart = (Multipart) message.Body; 

一旦我们有了multipart,我们就可以遍历它的 child :

foreach (var child in multipart) { 
    // ... 
} 

此时我们需要弄清楚 child 是否是另一个Multipart,一个MimePart (将代表文本或图像数据)或嵌入消息(又名 MessagePart )。

您可以使用 as 转换来快速推断出它是什么。

然后您只需继续遍历 MIME 实体树,直到找到您正在寻找的内容,这可能需要使用上述方法进行一些递归。

MimeKit 有一些替代方法可以做到这一点,但是:

  1. MimeMessage.BodyParts
  2. MimeIterator
  3. 和MimeVisitor

这是使用 BodyParts 属性快速解决问题的方法:

var myImage = message.BodyParts.OfType<MimePart> ().FirstOrDefault (x => x.IsMimeType ("image", "png"));