Тема кодирования на SmtpClient/MailMessage
Я пытаюсь отправить электронные письма, содержащие символы, отличные от ASCII, с помощью SmtpClient
и MailMessage
классы.
я использую внешнюю почтовую службу (MailChimp) и некоторые из моих писем были отклонены их SMTP-сервер. Я связался с ними и вот что они ответили:
похоже, что строка темы закодирована в Base64, а затем закодирована для печати, что обычно должно быть хорошо, но один из символов разбит на две линии. Поэтому, когда ваши строки темы немного длиннее, для правильной обработки они разбиты на две строки. При использовании UTF-8, цитируемой для печати в строке темы, символьные строки не должны прерываться между строками. Вместо этого строка должна быть закорочена так, чтобы полная символьная строка оставалась вместе. В этом случае этого не происходит, поэтому строка символов, представляющая один символ, разбивается на несколько строк и поэтому не является validly UTF-8 закодирован для печати.
проблемной темой является следующее:
Subject: XXXXXXX - 5 personnes vous ont nommé guide
, который, в UTF-8/в base64:
Subject: WFhYWFhYWCAtIDUgcGVyc29ubmVzIHZvdXMgb250IG5vbW3DqSBndWlkZQ==
поскольку этот заголовок превысит определенную максимальную длину (я не уверен, является ли это кодировкой для печати с кавычками и ее пределом 76 символов на строку или пределом заголовка SMTP), после кодирования и разделения заголовок станет:
Subject: =?utf-8?B?WFhYWFhYWCAtIDUgcGVyc29ubmVzIHZvdXMgb250IG5vbW3D?=
=?utf-8?B?qSBndWlkZQ==?=
по-видимому, это вызывает проблему при декодировании (поскольку первая строка не может быть декодирована в допустимую строку). Я не уверен, что полностью понимаю проблему, и у меня есть следующие вопросы:
- почему ?utf-8?Б? часть повторяется? Не должно ли кодирование QP происходить перед разделением строки и, следовательно, ее заголовок не должен повторяться?
- после QP-декодирования разве мы не должны получить действительную строку Base64 в 1 строке?
- в начале второй строки есть пробел, который находится вне QP кодирование, это может быть проблемой?
- сломан ли кодер, или это декодер?
также обратите внимание, что некоторые другие SMTP-серверы примут это сообщение, хотя это не означает, что оно действительно.
в качестве обходного пути я попытался отключить кодировку Base64, которая, по-видимому, не нужна, однако класс MailMessage имеет BodyTransferEncoding свойство, управляющее этой кодировкой, но только для основной части сообщения. Кажется, что никакое свойство не контролирует кодировку "передачи" предмета.
3 ответов
Это было подтверждено как ошибка в MSDN forums:
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
одна работа-это установить SubjectEncoding почтового сообщения в другая кодировка, например ISO-8859-1. В этом случае тема будет закодирована в кавычках для печати (не Base64), что позволяет избежать проблемы.
мое решение этой проблемы-это какой-то трюк!
Я использую персидский язык в теме почты, и я отправляю свою почту с помощью SmtpClient в .Net framework 4.5.2. тема полученного сообщения показывает некоторые мусорные слова в определенных позициях e.g 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 mail (и, возможно, другие веб-почтовые системы) игнорируют дополнительные пробелы и показывают тему, как ожидалось.
лучшее решение-использовать Encoding.Unicode
вместо Encoding.UTF8
на SubjectEncoding
.
похоже, что, поскольку реализация Microsoft просто игнорирует реальность UTF-16, способного кодировать символы более чем в двух байтах (как видно на почему C# использует UTF-16 для строк?), стабильный размер символа помогает.
Я видел это на https://gist.github.com/dbykadorov/9047455.