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 には、BodyPartBasic の子だけでなく、他の BodyPartMultipart の子も含めることができるため、別の BodyPartMultipart に遭遇した場合は、その中にも降りる必要があります。

あなたが調査しているメッセージにはマルチパートがネストされているため、問題が発生していると思います。

それまたは「添付ファイル」には、「添付ファイル」の値を持つ Content-Disposition ヘッダーがありません。

于 2014-11-25T22:21:57.707 に答える