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!
This commit is contained in:
Mechiel Lukkien 2025-02-15 10:04:01 +01:00
parent 93b627ceab
commit 46c1693ee9
No known key found for this signature in database
2 changed files with 10 additions and 7 deletions

View File

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

View File

@ -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