【问题标题】:How to download the attachments of a email using Mailkit如何使用 Mailkit 下载电子邮件的附件
【发布时间】:2015-01-23 18:27:39
【问题描述】:

我正在使用来自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);
            }
        }

【问题讨论】:

    标签: c# asp.net imap mime mailkit


    【解决方案1】:

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

    我的猜测是您正在检查的消息有嵌套的多部分,这就是您遇到问题的原因。

    那个或“附件”都没有值为“附件”的 Content-Disposition 标头。

    【讨论】:

    • 您能否提供任何示例或解决方法以通过上述过程下载附件。我是 MIME 树结构的新手,我会尝试查看您的文档。
    【解决方案2】:

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

    首先,创建一个递归函数,以IEnumerable&lt;BodyPartBasic&gt; 的形式检索所有基本正文部分(即 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 对象。这对我有用,但可能与其他人无关。这不是绝对必要的。

    我希望这对其他人有所帮助。

    【讨论】:

      猜你喜欢
      • 2018-03-04
      • 1970-01-01
      • 1970-01-01
      • 2014-08-01
      • 2016-10-06
      • 2019-05-17
      • 2023-03-18
      • 1970-01-01
      • 2019-06-18
      相关资源
      最近更新 更多