强制 System.Net.Mail.SmtpClient 使用 Base64 对主题标头进行编码

问题描述 投票:0回答:1

我们使用 .NET Core 3.1 的默认 SMTP 客户端发送电子邮件,如下所示:

private async Task SendMail(string from, string to, string subject, string body)
{
    var message = new MailMessage();

    message.From = new MailAddress(from);
    var toAddress = new MailAddress(to);
    message.To.Add(toAddress);

    message.Subject = subject;
    message.SubjectEncoding = Encoding.UTF8;
    message.Body = body;
    message.BodyEncoding = Encoding.UTF8;
    message.IsBodyHtml = false;

    using var smtp = new SmtpClient();
    smtp.Host = SMTP_HOST;
    smtp.Port = SMTP_PORT;
    smtp.EnableSsl = false;
    smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
    smtp.DeliveryFormat = SmtpDeliveryFormat.International;
    smtp.UseDefaultCredentials = false;
    smtp.Credentials = new NetworkCredential(SMTP_USER, SMTP_PASSWORD);

    await smtp.SendMailAsync(message);
}

然后我们这样调用该方法:

await this.SendMail(
    from: "[email protected]",
    to: "[email protected]",
    subject: "Caractères accentués",
    body: "dummy"
);

当使用网络分析仪检查主题标头的编码方式时,我们观察到以下情况:

  • 当客户端连接到支持 SMTPUTF8 的 MTA 时,主题标头将使用 UTF8 进行编码:
    Subject: Caractères accentués
  • 当客户端连接到不支持 SMTPUTF8 的 MTA 时,主题标头会先以 Base64 编码,然后再以 US-ASCII 编码:
    Subject: =?utf-8?B?Q2FyYWN0w6hyZXMgYWNjZW50dcOpcw==?=
  • 如果我们从
    SmtpDeliveryFormat.International
    切换到
    SmtpDeliveryFormat.SevenBits
    ,Subject 标头始终先以 Base64 编码,然后以 US-ASCII 编码(或者可能先以引用 url 编码,然后以 US-ASCII 编码)。

这都是标准和预期的行为。

我们使用第三方电子邮件服务作为 SMTP 中继,该服务本身支持 SMTPUTF8。但他们的服务有一个错误,无法检测到收件人方面缺乏 SMTPUTF8 支持,导致电子邮件主题在包含非 ASCII 字符时在我们的客户邮箱中显示不正确。他们使用我们在 MTA 中使用的相同编码发送主题,在我们的例子中是 UTF8,因为我们需要

SmtpDeliveryFormat.International
(为了与非 ASCII 电子邮件地址兼容)。

当我们使用 Base64 对主题标头进行编码时,该问题就会消失,因此我们希望将其作为一种解决方法,直到我们的提供商修复该问题为止。使用

smtp.DeliveryFormat = SmtpDeliveryFormat.SevenBits
可以实现这一点,但它也阻止我们在电子邮件地址中使用非 ASCII 字符,这是一个比主题编码问题更大的问题。所以我们不能这么做。

有没有办法强制 .NET 客户端对主题标头使用 Base64 编码,同时 also 使用

SmtpDeliveryFormat.International
,即使 SMTP 中继支持 SMTPUTF8?我尝试这样做:

message.Subject = $"=?utf-8?B?{Convert.ToBase64String(Encoding.UTF8.GetBytes(subject))}?=";

但是主题头没有被传递,它被

SmtpClient
解码,然后 UTF8 编码为
Caractères accentués
,所以它不会改变任何东西。

.net-core character-encoding smtp smtpclient system.net.mail
1个回答
1
投票

不是解决方案,而是解决方法:

当且仅当

目标邮件地址的
本地部分(即“@”之前的部分)包含非 ASCII 字符时,将 DeliveryFormat 设置为 SmtpDeliveryFormat.International。这具有以下效果:

  • 对于

    [email protected]

    ,主题将被正确编码。

  • 对于

    recipient@éxample.com

    ,一切都会正常工作:MailAddress 类可以使用 punycode 对邮件地址的主机部分进行编码,而不需要 SMTPUTF8。

  • 对于

    [email protected]

    ,主题不会进行 Base64 编码。 
    但是,由于本地部分包含非 ASCII 字符,因此收件人邮件服务器“极有可能”支持 SMTPUTF8,因此可以正确解释您的主题行。

    示例代码:
public static void EnableNonAsciiMailAddressesIfNecessary( SmtpClient client, MailMessage message) { var allAddresses = (message.From != null ? new[] { message.From } : Array.Empty<MailAddress>()). Concat(message.To). Concat(message.CC). Concat(message.Bcc). Concat(message.ReplyToList); var smtpUtf8Required = allAddresses.Any(a => a.User.Any(c => c > 0x7f)); if (smtpUtf8Required) { client.DeliveryFormat = SmtpDeliveryFormat.International; } }


© www.soinside.com 2019 - 2024. All rights reserved.