【问题标题】:C#: MailBee: Unload attachments inside a winmail.dat using mailbee's tnef utilitiesC#:MailBee:使用 mailbee 的 tnef 实用程序卸载 winmail.dat 中的附件
【发布时间】:2017-03-10 10:00:27
【问题描述】:

我正在尝试使用 gmail 收件箱中的 mailbee 阅读电子邮件。 我们的想法是获取任何 winmail.dat 并提取其附件并将它们添加到附件池中,这样我们就不必手动执行此操作。 MailBee 无法识别我与测试邮件一起发送的 winmail.dat 作为 Tnef 文件(该文件的类型是 Tnef 附件类型)。 IsTnef 结果为假。

我找不到很多关于 mailbee tnef 附件的信息,有什么想法吗?

这是我得到的:

var attachments = message.Attachments.Cast<MailBeeAttachment>().ToList();
var encapsulated = attachments.Where(a => a.IsTnef).SelectMany(a => a.GetAttachmentsFromTnef().Cast<MailBeeAttachment>());
// Add encapsulated attachments
attachments.AddRange(encapsulated);

【问题讨论】:

    标签: c# email gmail imap winmail.dat


    【解决方案1】:

    您可能希望继续使用 MailBee...但如果您愿意接受其他选择,让我回答这个问题,就像您使用我的开源库 MimeKit/MailKit 代替:

    当 MimeKit 的 MIME 解析器遇到带有与 application/vnd.ms-tnefapplication/ms-tnef 匹配的 Content-Type 标头的附件时,它将自动使用专用的 TnefPart 类来表示该附件。

    要从中提取封装的附件,您可以简单地使用 ExtractAttachments() 方法可能很像 MailBee 的 GetAttachmentsFromTnef() 方法。

    您的代码从 MailBee 到 MimeKit 的翻译如下所示:

    var attachments = message.Attachments.ToList();
    var encapsulated = attachments.OfType<TnefPart>().SelectMany(a => a.ExtractAttachments ());
    // Add encapsulated attachments
    attachments.AddRange(encapsulated);
    

    MailBee 的 IsTnef 属性返回 false 的原因很可能是因为 Content-Type 标头与我之前提到的 tnef mime-types 不匹配。如果确实如此,那么我上面发布的翻译后的代码在 MimeKit 下也会失败。

    不过……

    MimeKit 还提供了较低级别的 TNEF 支持类,如果您决定使用替代方法来确定 MIME 部分是否包含 TNEF 内容,则可以使用这些支持类。

    static void ExtractAttachments (MimePart attachment, IList<MimeEntity> attachments)
    {
        using (var reader = new TnefReader (attachment.ContentObject.Open (), 0, TnefComplianceMode.Loose)) {
            // skip past the non-attachment tnef content...
            while (reader.ReadNextAttribute ()) {
                if (reader.AttributeLevel == TnefAttributeLevel.Attachment)
                    break;
            }
    
            if (reader.AttributeLevel == TnefAttributeLevel.Attachment)
                ExtractAttachments (reader, attachments);
        }
    }
    
    static void ExtractAttachments (TnefReader reader, IList<MimeEntity> attachments)
    {
        var attachMethod = TnefAttachMethod.ByValue;
        var filter = new BestEncodingFilter ();
        var prop = reader.TnefPropertyReader;
        MimePart attachment = null;
        int outIndex, outLength;
        TnefAttachFlags flags;
        string[] mimeType;
        byte[] attachData;
        string text;
    
        do {
            if (reader.AttributeLevel != TnefAttributeLevel.Attachment)
                break;
    
            switch (reader.AttributeTag) {
            case TnefAttributeTag.AttachRenderData:
                attachMethod = TnefAttachMethod.ByValue;
                attachment = new MimePart ();
                break;
            case TnefAttributeTag.Attachment:
                if (attachment == null)
                    break;
    
                while (prop.ReadNextProperty ()) {
                    switch (prop.PropertyTag.Id) {
                    case TnefPropertyId.AttachLongFilename:
                        attachment.FileName = prop.ReadValueAsString ();
                        break;
                    case TnefPropertyId.AttachFilename:
                        if (attachment.FileName == null)
                            attachment.FileName = prop.ReadValueAsString ();
                        break;
                    case TnefPropertyId.AttachContentLocation:
                        text = prop.ReadValueAsString ();
                        if (Uri.IsWellFormedUriString (text, UriKind.Absolute))
                            attachment.ContentLocation = new Uri (text, UriKind.Absolute);
                        else if (Uri.IsWellFormedUriString (text, UriKind.Relative))
                            attachment.ContentLocation = new Uri (text, UriKind.Relative);
                        break;
                    case TnefPropertyId.AttachContentBase:
                        text = prop.ReadValueAsString ();
                        attachment.ContentBase = new Uri (text, UriKind.Absolute);
                        break;
                    case TnefPropertyId.AttachContentId:
                        attachment.ContentId = prop.ReadValueAsString ();
                        break;
                    case TnefPropertyId.AttachDisposition:
                        text = prop.ReadValueAsString ();
                        if (attachment.ContentDisposition == null)
                            attachment.ContentDisposition = new ContentDisposition (text);
                        else
                            attachment.ContentDisposition.Disposition = text;
                        break;
                    case TnefPropertyId.AttachData:
                        var stream = prop.GetRawValueReadStream ();
                        var content = new MemoryStream ();
                        var guid = new byte[16];
    
                        if (attachMethod == TnefAttachMethod.EmbeddedMessage) {
                            var tnef = new TnefPart ();
    
                            foreach (var param in attachment.ContentType.Parameters)
                                tnef.ContentType.Parameters[param.Name] = param.Value;
    
                            if (attachment.ContentDisposition != null)
                                tnef.ContentDisposition = attachment.ContentDisposition;
    
                            attachment = tnef;
                        }
    
                        // read the GUID
                        stream.Read (guid, 0, 16);
    
                        // the rest is content
                        using (var filtered = new FilteredStream (content)) {
                            filtered.Add (filter);
                            stream.CopyTo (filtered, 4096);
                            filtered.Flush ();
                        }
    
                        content.Position = 0;
    
                        attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit);
                        attachment.ContentObject = new ContentObject (content);
                        filter.Reset ();
    
                        attachments.Add (attachment);
                        break;
                    case TnefPropertyId.AttachMethod:
                        attachMethod = (TnefAttachMethod) prop.ReadValueAsInt32 ();
                        break;
                    case TnefPropertyId.AttachMimeTag:
                        mimeType = prop.ReadValueAsString ().Split ('/');
                        if (mimeType.Length == 2) {
                            attachment.ContentType.MediaType = mimeType[0].Trim ();
                            attachment.ContentType.MediaSubtype = mimeType[1].Trim ();
                        }
                        break;
                    case TnefPropertyId.AttachFlags:
                        flags = (TnefAttachFlags) prop.ReadValueAsInt32 ();
                        if ((flags & TnefAttachFlags.RenderedInBody) != 0) {
                            if (attachment.ContentDisposition == null)
                                attachment.ContentDisposition = new ContentDisposition (ContentDisposition.Inline);
                            else
                                attachment.ContentDisposition.Disposition = ContentDisposition.Inline;
                        }
                        break;
                    case TnefPropertyId.AttachSize:
                        if (attachment.ContentDisposition == null)
                            attachment.ContentDisposition = new ContentDisposition ();
    
                        attachment.ContentDisposition.Size = prop.ReadValueAsInt64 ();
                        break;
                    case TnefPropertyId.DisplayName:
                        attachment.ContentType.Name = prop.ReadValueAsString ();
                        break;
                    }
                }
                break;
            case TnefAttributeTag.AttachCreateDate:
                if (attachment != null) {
                    if (attachment.ContentDisposition == null)
                        attachment.ContentDisposition = new ContentDisposition ();
    
                    attachment.ContentDisposition.CreationDate = prop.ReadValueAsDateTime ();
                }
                break;
            case TnefAttributeTag.AttachModifyDate:
                if (attachment != null) {
                    if (attachment.ContentDisposition == null)
                        attachment.ContentDisposition = new ContentDisposition ();
    
                    attachment.ContentDisposition.ModificationDate = prop.ReadValueAsDateTime ();
                }
                break;
            case TnefAttributeTag.AttachTitle:
                if (attachment != null && string.IsNullOrEmpty (attachment.FileName))
                    attachment.FileName = prop.ReadValueAsString ();
                break;
            case TnefAttributeTag.AttachMetaFile:
                if (attachment == null)
                    break;
    
                // TODO: what to do with the meta data?
                break;
            case TnefAttributeTag.AttachData:
                if (attachment == null || attachMethod != TnefAttachMethod.ByValue)
                    break;
    
                attachData = prop.ReadValueAsBytes ();
                filter.Flush (attachData, 0, attachData.Length, out outIndex, out outLength);
                attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.EightBit);
                attachment.ContentObject = new ContentObject (new MemoryStream (attachData, false));
                filter.Reset ();
    
                attachments.Add (attachment);
                break;
            }
        } while (reader.ReadNextAttribute ());
    }
    

    当然……你也可以这样作弊:

    var tnef = new TnefPart { ContentObject = attachment.ContentObject };
    attachments.AddRange (tnef.ExtractAttachments ());
    

    所以最终结果可能如下所示(如果您决定改为匹配 FileName):

    var attachments = message.Attachments.ToList();
    var encapsulated = attachments.OfType<MimePart>()
        .Where(x => (x is TnefPart) || x.FileName == "winmail.dat")
        .SelectMany(x => {
            var tnef = (x as TnefPart) ?? new TnefPart { ContentObject = x.ContentObject };
            return tnef.ExtractAttachments ();
        });
    // Add encapsulated attachments
    attachments.AddRange(encapsulated);
    

    【讨论】:

      【解决方案2】:

      您不应该在测试时手动添加 winmail.dat。它总是由 MS Exchange 或 Outlook 以特殊方式生成(和附加)。 IsTnef 将从真实的(Outlook 或 Exchange 生成的)电子邮件中返回真实的附件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-19
        • 1970-01-01
        • 2015-04-14
        • 1970-01-01
        • 1970-01-01
        • 2023-04-07
        • 2021-11-30
        • 2017-08-09
        相关资源
        最近更新 更多