简体   繁体   English

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

[英]How to download the attachments of a email using Mailkit

I'm using the code from here to download attachments from mail using MailKit. 我正在使用此处的代码使用MailKit从邮件中下载附件。 In the foreach loop where attachments are retrieved, it is always returning empty. 在检索附件的foreach循环中,它总是返回空。 As it is empty it is not entering the foreach loop. 由于它为空,因此不会进入foreach循环。 Please correct me if i'm doing anything wrong. 如果我做错了什么,请纠正我。

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

Here's what I'm using to traverse the MIME tree structure to get all possible attachments out. 这就是我用来遍历MIME树结构以获取所有可能的附件的内容。 Note that at least in the case of the emails I was testing, the IsAttachment flag was never set to true . 请注意,至少在我正在测试的电子邮件中, IsAttachment标志从未设置为true

First, make a recursive function that retrieves all basic body parts (which are the parts of the MIME message that contains the actual content of the message) as an IEnumerable<BodyPartBasic> : 首先,创建一个递归函数,以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;
    }
}

And then put that function to use within a "download" function that is very similar to what @jstedfast has provided in other posts: 然后将该函数在“下载”函数中使用,该函数与@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);
    }
}

Note that this function: 请注意此功能:

  • Skips files that haven't a filename. 跳过没有文件名的文件。 If you want to keep those files, you could add in the unnamed counter from @jstedfast's other examples. 如果要保留这些文件,可以从@jstedfast的其他示例中添加unnamed计数器。 You could also add in other logic to filter out files based on filename or other information you'd get in the MIME header. 您还可以添加其他逻辑,以根据文件名或在MIME标头中获得的其他信息过滤掉文件。
  • First downloads only the header of the attachment. 首先仅下载附件的标题。 This allows for filename filtering without having to download the content first. 这允许文件名过滤,而不必先下载内容。
  • Is an extension method and can thus be used like: client.DownloadAttachments(someMessage, @"C:\\tmp\\attachments") 是一种扩展方法,因此可以像这样使用: client.DownloadAttachments(someMessage, @"C:\\tmp\\attachments")
  • Returns System.IO.FileInfo objects for each attachment saved. 返回每个保存的附件的System.IO.FileInfo对象。 This was useful for me but may not be relevant to others. 这对我很有用,但可能与其他人无关。 It's not strictly necessary. 这不是绝对必要的。

I hope this helps other folks. 我希望这对其他人有帮助。

The first thing to note is that MIME is a tree structure and not a flat list. 首先要注意的是MIME是树结构而不是平面列表。 A BodyPartMultipart can contain other BodyPartMultipart children as well as BodyPartBasic children, so when you come across another BodyPartMultipart, you need to descend into that as well. BodyPartMultipart可以包含其他BodyPartMultipart子代以及BodyPartBasic子代,因此当您遇到另一个BodyPartMultipart时,您也需要进入该子代。

My guess is that the messages you are examining have nested multiparts and that is why you are having trouble. 我的猜测是您正在检查的消息具有嵌套的多个部分,这就是您遇到麻烦的原因。

Either that or the "attachments" do not have a Content-Disposition header with a value of "attachment". 那个或“附件”都没有一个值为“ attachment”的Content-Disposition标头。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM