6

我正在创建一封来自 BizTalk 2016 SMTP 发送端口的带有 MIME 附件的电子邮件。但是,我认为任何人都可以从任何其他语言分享有关 Outlook 和 MIME 的奇怪之处的任何知识可能会帮助我解决以下问题。

在 Outlook 中,附件显示为 body.txt,但是当我单击“文件保存”时,它会显示我创建它时使用的名称(这就是用户想要看到的)。

我指的是左侧,它在 5k 上方显示“body.txt”,在下面的屏幕截图中附件图标的右侧:

在此处输入图像描述

在 BizTalk C# Pipeline 组件中,该附件是使用以下代码设置的,我们在其中设置 BizTalk 消息的上下文属性。我还尝试设置 ContentHeader 和 ContentID。

strFilename = "MyFileName_693.txt";  // Just for example. 
pInMsg.BodyPart.PartProperties.Write(
              "FileName",
              "http://schemas.microsoft.com/BizTalk/2003/mime-properties",
               strFilename);

当我将电子邮件转发到我的 Gmail 时,附件以正确的名称显示。所以我的问题特别是让它在 Outlook (2016) 中以所需的名称出现。

4

1 回答 1

2

到目前为止,我已经使用带有动态发送端口的编排工作。它仍然需要做一些工作,但它可以使用库存组件完成工作。以下描述基于 BizTalk 2013R2 中包含的库存 SMTP 适配器。

注意:即使我的解决方案有效,但如果适配器对此稍微聪明一点,它感觉就像是一种解决方法并且我不应该做的事情。

首先,让我们看一下导致某些客户端出现问题的示例电子邮件片段:

------=_NextPart_000_0001_01D4502F.8A6A1500
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="utf-8"

See attached email.
------=_NextPart_000_0001_01D4502F.8A6A1500
Content-Type: application/pdf; name="CDM_Order - Copy.pdf"
Content-Disposition: attachment; filename="CDM_Order - Copy.pdf"
Content-Description: body
Content-Transfer-Encoding: base64

JVBERi0xLjQKJeLjz9MNCjUgMCBvYmoKPDwvRFsgMyAwIFIvWFlaIG51bGwgODQxLjg4OTc3IG51
bGwgXQo+PgplbmRvYmoKOCAwIG9iago8PC9EWyAzIDAgUi9YWVogbnVsbCAyOTAuMjM2NTcgbnVs
bCBdCj4+ (etc etc base64 your file)...

注意Content-Description: body部分。这就是为什么一些客户阅读body.xml或在我的情况下的原因body.pdf,即使 Disposition 部分看起来很棒:Content-Disposition: attachment; filename="CDM_Order - Copy.pdf"

硬设置MIME.FileName不仅会起作用,即使它 Content-Disposition最终会设置正确,它也永远不会更新Content-Description. 这是因为您在静态发送端口上设置了或在动态发送端口上Attach only body part指定了相应的数值。1

但是,它将与 type 的Attach all partsor2值一起使用MessagePartsAttachments。这涉及在您的编排中制作多部分消息。这将有两个部分;

  • 第一个是BodyPart,现在这个将包含您的消息文本而不是您的附件。确保您Message Body PartMessage Type.
  • 第二部分将是您的实际附件,根据您的附件类型指定此类型。我Attachment在这个例子中命名了这个。

现在你可能会认为它也会发送BodyPart附件,因为我说过我们需要Attach all parts。这是真的,因此要更正它,您BodyPart必须定义为 a RawString,这会将字符串转换为 BizTalk 消息部分中的纯文本。为了完整起见,我将 C# 类放在底部以供参考。

现在它被定义为 a RawString,SMTP 适配器将把它作为正文而不是附件。作为副作用,SMTP 适配器将不再将该Content-Description: body部分放在附件部分中,而是放在实际的正文部分中。它看起来像这样:

------=_NextPart_000_0001_01D450E4.A7E9A5E0
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="utf-8"
Content-Description: body

See attached email.
------=_NextPart_000_0001_01D450E4.A7E9A5E0
Content-Type: application/pdf; name="ID_0_Nummer_0.pdf"
Content-Disposition: attachment; filename="ID_0_Nummer_0.pdf"
Content-Transfer-Encoding: base64

JVBERi0xLjQKJeLjz9MNCjUgMCBvYmoKPDwvRFsgMyAwIFIvWFlaIG51bGwgODQxLjg4OTc3IG51
bGwgXQo+PgplbmRvYmoKOCAwIG9iago8PC9EWyAzIDAgUi9YWVogbnVsbCAyOTAuMjM2NTcgbnVs
bCBdCj4+ (etc etc base64 your file)...

除了零件的位置,真的没有什么不同Content-Description: body,这正是我们想要的。现在,电子邮件对于每个客户来说都很好。

除了我已经提到的那些之外,最重要的属性也必须设置为使其正常运行:

您的正文内容类型:

MsgPdfOrder.BodyPart(Microsoft.XLANGs.BaseTypes.ContentType) = "text/plain";

附件的内容类型:

MsgPdfOrder.Attachment(Microsoft.XLANGs.BaseTypes.ContentType) = "application/pdf";

附件文件名:

MsgPdfOrder.Attachment(MIME.FileName) =  "CDM_Order - Copy.pdf"

正文字符集(如果未设置将导致Unknown Error Description):

MsgPdfOrder(SMTP.EmailBodyTextCharset) = "UTF-8";

确保你没有设置,SMTP.EmailBodyText因为我们已经有了BodyPart

RawString 类,在编排中像这样使用它MsgPdfOrder.BodyPart = new Yournamespace.Components.RawString("See attached email.");

using System.Runtime.Serialization;
using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Microsoft.XLANGs.BaseTypes;

namespace Yournamespace.Components
{
    public abstract class BaseFormatter : IFormatter
    {
        public virtual SerializationBinder Binder
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public virtual StreamingContext Context
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public virtual ISurrogateSelector SurrogateSelector
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public abstract void Serialize(Stream stm, object obj);
        public abstract object Deserialize(Stream stm);
    }

    public class RawStringFormatter : BaseFormatter
    {
        public override void Serialize(Stream s, object o)
        {
            RawString rs = (RawString)o;
            byte[] ba = rs.ToByteArray();
            s.Write(ba, 0, ba.Length);
        }

        public override object Deserialize(Stream stm)
        {
            StreamReader sr = new StreamReader(stm, true);
            string s = sr.ReadToEnd();
            return new RawString(s);
        }
    }

    [CustomFormatter(typeof(RawStringFormatter))]
    [Serializable]
    public class RawString
    {
        [XmlIgnore]
        string _val;

        public RawString(string s)
        {
            if (null == s)
                throw new ArgumentNullException();
            _val = s;
        }

        public RawString()
        {
        }

        public byte[] ToByteArray()
        {
            return Encoding.UTF8.GetBytes(_val);
        }

        public override string ToString()
        {
            return _val;
        }
    }
}
于 2018-09-20T13:38:50.813 回答