.net-corecharacter-encodingsmtpsmtpclientsystem.net.mail

Force System.Net.Mail.SmtpClient to encode the Subject header using Base64


We are using .NET Core 3.1's default SMTP client to send an email, like this:

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);
}

Then we call the method like this:

await this.SendMail(
    from: "noreply@ourdomain.com",
    to: "recipient@example.com",
    subject: "Caractères accentués",
    body: "dummy"
);

When using a network analyzer to check how the Subject header is encoded, we are observing the following:

This is all standard and excpected behaviour.

We are using a third party email service as a SMTP relay, which supports SMTPUTF8 itself. But their service has a bug and fails to detect the lack of SMTPUTF8 support on recipient's side, resulting in email Subjects being improperly displayed in our clients mailboxes when they contain non-ASCII characters. They send the Subject with the same encoding we used with their MTA, which in our case is UTF8, because we need SmtpDeliveryFormat.International (for compatibility with non-ASCII email addresses).

The issue disappears when we encode the Subject header using Base64, so we would like to do that as a workaround until our provider fixes the issue on their side. Using smtp.DeliveryFormat = SmtpDeliveryFormat.SevenBits achieves this, but it also prevents us from using non-ASCII characters in email addresses, which is an even bigger problem than the Subject encoding issue. So we can't do that.

Is there a way to force the .NET client to use Base64 encoding for the Subject header while also using SmtpDeliveryFormat.International, even when the SMTP relay supports SMTPUTF8? I tried to do this:

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

But the subject header is not passed through, it is decoded by the SmtpClient then UTF8-encoded as Caractères accentués, so it doesn't change anything.


Solution

  • Not a solution, but a workaround:

    Set DeliveryFormat to SmtpDeliveryFormat.International if, and only if, the local part (i.e. the part before the "@") of the target mail address contains a non-ascii character. This has the following effect:

    Example code:

    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;
        }
    }