我正在尝试使用SmtpClient
和MailMessage
类发送包含非ASCII字符的电子邮件。
我正在使用外部邮件服务(MailChimp),我的部分电子邮件已被其SMTP服务器拒绝。我联系了他们,这就是他们回复的内容:
主题行似乎是Base64编码,然后是Quoted-Printable编码,通常应该没问题,但其中一个字符被分成两行。因此,当您的主题行有点长时,为了正确处理,它会被分为两行。当在主题行中使用UTF-8引用可打印时,不应该在行之间断开字符串。相反,应该缩短一行,以便将完整的字符串保持在一起。在这种情况下,没有发生这种情况,因此表示单个字符的字符串在多行中被破坏,因此无法有效地使用UTF-8引用 - 可打印编码。
问题主题如下:
Subject: XXXXXXX - 5 personnes vous ont nommé guide
这是UTF-8 / Base64:
Subject: WFhYWFhYWCAtIDUgcGVyc29ubmVzIHZvdXMgb250IG5vbW3DqSBndWlkZQ==
因为该标头超过了某个最大长度(我不确定它是Quoted-Printable编码及其每行76个字符的限制,还是SMTP标头限制),在编码和拆分后,标头将变为:
Subject: =?utf-8?B?WFhYWFhYWCAtIDUgcGVyc29ubmVzIHZvdXMgb250IG5vbW3D?=
=?utf-8?B?qSBndWlkZQ==?=
显然,这会在解码时导致问题(因为第一行无法解码为有效字符串)。我不确定我是否完全理解这个问题,我有以下问题:
另请注意,其他一些SMTP服务器会接受此消息,但这并不意味着它有效。
作为一种解决方法,我尝试禁用Base64编码,这显然是不必要的,但MailMessage类具有控制此编码的BodyTransferEncoding属性,但仅适用于邮件的正文部分。没有属性似乎控制主题的“转移”编码。
答案 0 :(得分:5)
这被证实是MSDN论坛中的一个错误:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/4d1c1752-70ba-420a-9510-8fb4aa6da046/subject-encoding-on-smtpclientmailmessage
在Microsoft Connect上提交了一个错误: https://connect.microsoft.com/VisualStudio/feedback/details/785710/mailmessage-subject-incorrectly-encoded-in-utf-8-base64
一种解决方法是将MailMessage的SubjectEncoding设置为其他编码,例如ISO-8859-1。在这种情况下,主题将在Quoted Printable(而不是Base64)中进行编码,以避免出现此问题。
答案 1 :(得分:1)
更好的解决方案是Encoding.Unicode
使用Encoding.UTF8
代替SubjectEncoding
。
看起来,由于Microsoft实现只是忽略了UTF-16能够以超过两个字节编码字符的现实(如Why does C# use UTF-16 for strings?所示),稳定的字符大小有帮助。
我已在https://gist.github.com/dbykadorov/9047455上看到过这种情况。
答案 2 :(得分:0)
我对这个问题的解决方法是某种伎俩!
我在邮件主题中使用波斯语,我在.Net framework 4.5.2中使用SmtpClient发送邮件。 收到的消息主题在某些位置显示一些垃圾字,例如主题字符串中的第18和第38个字符。无论主题是什么。
然后我尝试在这些位置插入一些空格(字符32),重新发送邮件后结果非常好。 unicode主题按预期显示。
所以我写了一个函数在我所需的位置插入6个空格(避免在单词中插入空格),如下所示:
private static string InsertSpacesBetweenWords(this string subject , int where)
{
int l;
int i=1;
string[] s = subject.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
string output = "";
if (s.Length > 0) output += s[0] + " ";
l = output.Length;
bool done = false;
while (i < s.Length)
{
if (!done)
{
if ((s[i] + output).Length > where)
{
for (int j = output.Length; j < where + 6; j++)
output += " ";
done = true;
}
}
output += s[i] + " ";
i++;
}
return output;
}
然后我使用此功能转换邮件主题:
mail.Subject = mySubject.InsertSpacesBetweenWords(38).InsertSpacesBetweenWords(18);
有趣的是,Gmail和Yahoo邮件(可能还有其他基于Web的邮件系统)会忽略额外的空格并按预期显示主题。
答案 3 :(得分:0)