1

我正在使用此处的代码使用 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);
            }
        }
4

2 回答 2

2

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

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

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);
    }
}

注意这个函数:

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

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

于 2015-05-04T12:55:38.500 回答
1

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

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

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

于 2014-11-25T22:21:57.707 回答