如何使用Mailkit下载电子邮件的附件

时间:2014-11-25 16:35:20

标签: c# asp.net imap mime mailkit

我正在使用here中的代码使用MailKit从邮件下载附件。在检索附件的foreach循环中,它始终返回空。因为它是空的,所以它不会进入foreach循环。如果我做错了,请纠正我。

        var messages = client.Inbox.Fetch(0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId);
        int unnamed = 0;

        foreach (var message in messages)
        {
            var multipart = message.Body as BodyPartMultipart;
            var basic = message.Body as BodyPartBasic;

            if (multipart != null)
            {

                //Here the attachments is always empty even though my mail has email with attachements
                var attachments = multipart.BodyParts.OfType<BodyPartBasic>().Where(x => x.IsAttachment);
                foreach (var attachment in attachments)
                {
                    var mime = (MimePart)client.Inbox.GetBodyPart(message.UniqueId.Value, attachment);
                    var fileName = mime.FileName;

                    if (string.IsNullOrEmpty(fileName))
                        fileName = string.Format("unnamed-{0}", ++unnamed);

                    using (var stream = File.Create(fileName))
                        mime.ContentObject.DecodeTo(stream);
                }
            }
            else if (basic != null && basic.IsAttachment)
            {
                var mime = (MimePart)client.Inbox.GetBodyPart(message.UniqueId.Value, basic);
                var fileName = mime.FileName;

                if (string.IsNullOrEmpty(fileName))
                    fileName = string.Format("unnamed-{0}", ++unnamed);

                using (var stream = File.Create(fileName))
                    mime.ContentObject.DecodeTo(stream);
            }
        }

2 个答案:

答案 0 :(得分:2)

这是我用来遍历MIME树结构以获取所有可能的附件的内容。请注意,至少在我测试的电子邮件的情况下,IsAttachment标记从未设置为true

首先,创建一个递归函数,以IEnumerable<BodyPartBasic>的形式检索所有基本正文部分(包含消息实际内容的MIME消息部分):

private static IEnumerable<BodyPartBasic> GetBasicBodyParts(this BodyPart part)
{
    var multipart = part as BodyPartMultipart;
    var basic = part as BodyPartBasic;
    if (multipart != null)
    {
        foreach (var subPart in multipart.BodyParts)
        {
            if (subPart is BodyPartBasic)
            {
                yield return subPart as BodyPartBasic;
            }
            else
            {
                foreach (var subSubPart in subPart.GetBasicBodyParts())
                {
                    yield return subSubPart;
                }
            }
        }
    } else if (basic != null)
    {
        yield return basic;
    }
    else
    {
        yield break;
    }
}

然后将该功能用于“下载”功能,该功能与@jstedfast在其他帖子中提供的功能非常相似:

public static IEnumerable<FileInfo> DownloadAttachments(this EmailClient client, IMessageSummary message,
    string destination)
{
    fileNameFilter = fileNameFilter ?? AlwaysTrue;
    if (!Directory.Exists(destination))
        Directory.CreateDirectory(destination);

    var folder = client.Inbox;
    folder.Open(FolderAccess.ReadOnly);
    foreach (var part in message.Body.GetBasicBodyParts())
    {

        var mimeHeader = (MimePart) folder.GetBodyPart(message.UniqueId.Value, part, headersOnly: true);
        var headerFileName = mimeHeader.FileName;
        if (string.IsNullOrWhiteSpace(headerFileName))
            continue;


        var mime = (MimePart) folder.GetBodyPart(message.UniqueId.Value, part);
        var fileName = mime.FileName;

        var filePath = Path.Combine(destination, fileName);
        using (var stream = File.Create(filePath))
            mime.ContentObject.DecodeTo(stream);

        yield return new FileInfo(filePath);
    }
}

请注意此功能:

  • 跳过没有文件名的文件。如果你想保留这些文件,可以在@jstedfast的其他例子中添加unnamed计数器。您还可以添加其他逻辑,以根据您在MIME标头中获得的文件名或其他信息过滤掉文件。
  • 首先只下载附件的标题。这允许进行文件名过滤而无需先下载内容。
  • 是一种扩展方法,因此可以像client.DownloadAttachments(someMessage, @"C:\tmp\attachments")
  • 一样使用
  • 为保存的每个附件返回System.IO.FileInfo个对象。这对我有用,但可能与其他人无关。这不是绝对必要的。

我希望这有助于其他人。

答案 1 :(得分:0)

首先要注意的是MIME是树结构,而不是平面列表。 BodyPartMultipart可以包含其他BodyPartMultipart子节点以及BodyPartBasic子节点,因此当您遇到另一个BodyPartMultipart时,您也需要进入其中。

我的猜测是你正在检查的邮件有嵌套的多部分,这就是你遇到麻烦的原因。

要么是&#34;附件&#34;没有Content-Disposition标头,其值为&#34;附件&#34;。