如何使用 Mailkit 读取电子邮件正文中的内联图像
How to read inline image in email body using Mailkit
我给自己发了一封测试邮件,邮件正文中有一张图片。此图片不是附件,只是粘贴到电子邮件正文中。
我正在使用 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 and/or the README了解 MIME 的结构,以便对此类问题的回答变得显而易见,但与此同时...
首先要理解MIME是一个树形结构,这意味着有一个根节点(可能是也可能不是leaf-node),可以有分支节点(例如multipart/mixed
、multipart/alternative
、multipart/related
等),还有 leaf-node(例如 text/plain
、text/html
、image/jpeg
、application/octet-stream
, 等等).
MIME结构的根节点是MimeMessage.Body属性.
如果邮件仅包含一个 text/plain
MIME 实体,则 MimeMessage.Body
节点将 成为 那个 text/plain
MIME 实体。
在你的情况下,听起来你至少有一个 text/html
实体和一个 image/png
实体。
对您的消息结构一无所知,我们可以得出结论 MimeMessage.Body
既不是 text/html
实体也不是 image/png
实体,因为您只能有 1 个根节点text/*
和 image/*
部分是 leaf-node 实体,而不是分支节点实体。
这意味着 MimeMessage.Body
将是一个 multipart/*
,它将由 Multipart(或其子类)表示。
因为很明显你的 MimeMessage.Body
是 Multipart
,我们可以转换它:
var multipart = (Multipart) message.Body;
一旦我们有了 multipart
,我们就可以迭代它的 children:
foreach (var child in multipart) {
// ...
}
此时我们需要弄清楚child是否是另一个Multipart
,一个MimePart (which will represent text or image data), or an embedded message (aka MessagePart)。
您可以使用 as
转换来快速推断出它是什么。
然后您只需继续遍历 MIME 实体树,直到找到您正在寻找的内容,这可能需要使用上述方法进行一些递归。
MimeKit 有一些替代方法可以做到这一点,但是:
这是使用 BodyParts
属性:
快速解决您的问题的方法
var myImage = message.BodyParts.OfType<MimePart> ().FirstOrDefault (x => x.IsMimeType ("image", "png"));
我给自己发了一封测试邮件,邮件正文中有一张图片。此图片不是附件,只是粘贴到电子邮件正文中。
我正在使用 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 and/or the README了解 MIME 的结构,以便对此类问题的回答变得显而易见,但与此同时...
首先要理解MIME是一个树形结构,这意味着有一个根节点(可能是也可能不是leaf-node),可以有分支节点(例如multipart/mixed
、multipart/alternative
、multipart/related
等),还有 leaf-node(例如 text/plain
、text/html
、image/jpeg
、application/octet-stream
, 等等).
MIME结构的根节点是MimeMessage.Body属性.
如果邮件仅包含一个 text/plain
MIME 实体,则 MimeMessage.Body
节点将 成为 那个 text/plain
MIME 实体。
在你的情况下,听起来你至少有一个 text/html
实体和一个 image/png
实体。
对您的消息结构一无所知,我们可以得出结论 MimeMessage.Body
既不是 text/html
实体也不是 image/png
实体,因为您只能有 1 个根节点text/*
和 image/*
部分是 leaf-node 实体,而不是分支节点实体。
这意味着 MimeMessage.Body
将是一个 multipart/*
,它将由 Multipart(或其子类)表示。
因为很明显你的 MimeMessage.Body
是 Multipart
,我们可以转换它:
var multipart = (Multipart) message.Body;
一旦我们有了 multipart
,我们就可以迭代它的 children:
foreach (var child in multipart) {
// ...
}
此时我们需要弄清楚child是否是另一个Multipart
,一个MimePart (which will represent text or image data), or an embedded message (aka MessagePart)。
您可以使用 as
转换来快速推断出它是什么。
然后您只需继续遍历 MIME 实体树,直到找到您正在寻找的内容,这可能需要使用上述方法进行一些递归。
MimeKit 有一些替代方法可以做到这一点,但是:
这是使用 BodyParts
属性:
var myImage = message.BodyParts.OfType<MimePart> ().FirstOrDefault (x => x.IsMimeType ("image", "png"));