如何设置附件名称以在Outlook中正确显示
我正在使用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)中显示所需的名称。
到目前为止,我已经使用动态发送端口的业务流程。 它仍然有点工作,但它完成了库存组件的工作。 以下描述基于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"
Content-Disposition: attachment; filename="CDM_Order - Copy.pdf"
。
硬设置MIME.FileName
不仅可以工作,即使它最终会设置Content-Disposition
,它也永远不会更新Content-Description
。 这是因为在静态发送端口上,您已设置Attach only body part
或者您在动态发送端口上指定了相应的数值1
。
但是,它将与MessagePartsAttachments
类型的Attach all parts
或2
值一起使用。 这涉及在业务流程中制作多部分消息。 这将有两个部分;
- 第一个是
BodyPart
,现在这个将包含您的消息文本,而不是您的附件。 确保在Message Type
将此指定为Message Body Part
。 - 第二部分将是您的实际附件,根据您的附件类型指定此类型。 我在这个例子中命名了这个
Attachment
。
现在您可能会认为它会将BodyPart
作为附件发送,因为我已经说过我们需要Attach all parts
。 这是事实,因此要纠正这一点,必须将BodyPart
定义为RawString
,这会将字符串转换为BizTalk消息部分中的纯文本。 为了完整性,我将把C#类放在底部以供参考。
现在它被定义为RawString
,SMTP适配器将把它作为正文而不是附件。 作为副作用,SMTP适配器将不再将Content-Description: body
部分放在附件部分中,而是放在实际的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; } } }