如何设置附件名称以在 Outlook 中正确显示
How Set Attachment Name to Show Properly in Outlook
我正在使用 BizTalk 2016 SMTP 发送端口创建带有 MIME 附件的电子邮件。
但是,我认为任何人都可以从任何其他语言分享有关 Outlook 和 MIME 的奇怪之处的任何知识可能会帮助我解决下面的问题。
在 Outlook 中,附件显示为 body.txt,但是当我单击 "File Save" 时,它显示的是我创建它时使用的名称(这是用户希望看到的)。
我指的是 5k 上方的左侧 "body.txt" 和下面屏幕截图中附件图标的右侧:
在 BizTalk C# 管道组件中,该附件是使用以下代码设置的,我们在其中设置 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
的原因,即使处置部分看起来很棒: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# class 放在底部以供参考。
现在它被定义为 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 class,在编排中像这样使用它 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;
}
}
}
我正在使用 BizTalk 2016 SMTP 发送端口创建带有 MIME 附件的电子邮件。 但是,我认为任何人都可以从任何其他语言分享有关 Outlook 和 MIME 的奇怪之处的任何知识可能会帮助我解决下面的问题。
在 Outlook 中,附件显示为 body.txt,但是当我单击 "File Save" 时,它显示的是我创建它时使用的名称(这是用户希望看到的)。
我指的是 5k 上方的左侧 "body.txt" 和下面屏幕截图中附件图标的右侧:
在 BizTalk C# 管道组件中,该附件是使用以下代码设置的,我们在其中设置 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
的原因,即使处置部分看起来很棒: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# class 放在底部以供参考。
现在它被定义为 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 class,在编排中像这样使用它 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;
}
}
}