From 46c1693ee9353fb1838ca0fb8c3ec81874f21823 Mon Sep 17 00:00:00 2001 From: Mechiel Lukkien Date: Sat, 15 Feb 2025 10:04:01 +0100 Subject: [PATCH] when delivering over smtp, do not require the other server to announce the 8bitmime extension unless in pedantic mode all relevant systems nowadays should be accepting "8-bit" messages. before this change, we would fail delivery for 8bit messages when the remote server doesn't announce the 8bitmime smtp extension. even though that system would likely just accept our message. also, there's a good chance the non-8bitmime-supporting system is some intermediate minimal mail server like openbsd spamd, which was fixed to announce the 8bitmime extension in the past year. in theory, we could rewrite the message to be 7bit-only if it is a mime message. but it's probably not worth the trouble. also see https://cr.yp.to/smtp/8bitmime.html as alternative to PR #287 by mattanja (who also reported the issue on matrix), thanks! --- queue/direct.go | 8 +++++++- smtpclient/client.go | 9 +++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/queue/direct.go b/queue/direct.go index 6072fd6..1129b2e 100644 --- a/queue/direct.go +++ b/queue/direct.go @@ -728,7 +728,13 @@ func deliverHost(log mlog.Log, resolver dns.Resolver, dialer smtpclient.Dialer, rcpts[i] = mr.msg.Recipient().XString(m0.SMTPUTF8) } - resps, err := sc.DeliverMultiple(ctx, mailFrom, rcpts, size, msg, has8bit, smtputf8, m0.RequireTLS != nil && *m0.RequireTLS) + // Only require that remote announces 8bitmime extension when in pedantic mode. All + // relevant systems nowadays should accept "8-bit" messages, some unfortunately + // don't announce support. In theory we could rewrite the submitted message to be + // 7-bit-only, but the trouble likely isn't worth it. + req8bit := has8bit && mox.Pedantic + + resps, err := sc.DeliverMultiple(ctx, mailFrom, rcpts, size, msg, req8bit, smtputf8, m0.RequireTLS != nil && *m0.RequireTLS) if err != nil && (len(resps) == 0 && n == len(msgResps) || len(resps) == len(msgResps)) { // If error and it applies to all recipients, return a single error. return deliverResult{err: inspectError(err)} diff --git a/smtpclient/client.go b/smtpclient/client.go index ee7380b..04e4524 100644 --- a/smtpclient/client.go +++ b/smtpclient/client.go @@ -1095,8 +1095,8 @@ func (c *Client) TLSConnectionState() *tls.ConnectionState { // mailFrom must be an email address, or empty in case of a DSN. rcptTo must be // an email address. // -// If the message contains bytes with the high bit set, req8bitmime must be true. If -// set, the remote server must support the 8BITMIME extension or delivery will +// If the message contains bytes with the high bit set, req8bitmime should be true. +// If set, the remote server must support the 8BITMIME extension or delivery will // fail. // // If the message is internationalized, e.g. when headers contain non-ASCII @@ -1149,10 +1149,7 @@ func (c *Client) DeliverMultiple(ctx context.Context, mailFrom string, rcptTo [] } if !c.ext8bitmime && req8bitmime { - // Temporary error, e.g. OpenBSD spamd does not announce 8bitmime support, but once - // you get through, the mail server behind it probably does. Just needs a few - // retries. - c.xerrorf(false, 0, "", "", nil, "%w", Err8bitmimeUnsupported) + c.xerrorf(true, 0, "", "", nil, "%w", Err8bitmimeUnsupported) } if !c.extSMTPUTF8 && reqSMTPUTF8 { // ../rfc/6531:313