Skip to content

Commit

Permalink
queue: retry with another IP when first attempt fails for dualstack r…
Browse files Browse the repository at this point in the history
…emote servers

mox was already giving another try for received errors after the
`HELO`/`EHLO` command. Now mox do the same for received errors when
trying to deliver the message to the remote SMTP server.

This should help to deliver messages to SMTP server that rejects
incoming messages because of bad ipv4 or ipv6 configuration (for example
for servers checking reverse DNS records). mox will now try to deliver
messages on both ip family instead before considering the error as
permanent.

fix #149
  • Loading branch information
lmeunier committed Apr 12, 2024
1 parent d74610c commit feb8e6c
Showing 1 changed file with 10 additions and 4 deletions.
14 changes: 10 additions & 4 deletions queue/direct.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,23 +639,29 @@ func deliverHost(log mlog.Log, resolver dns.Resolver, dialer smtpclient.Dialer,
err = fmt.Errorf("storing recipient domain tls status: %w", err)
}
}
if err != nil {

inspectError := func(err error) error {
if cerr, ok := err.(smtpclient.Error); ok {
// If we are being rejected due to policy reasons on the first
// attempt and remote has both IPv4 and IPv6, we'll give it
// another try. Our first IP may be in a block list, the address for
// the other family perhaps is not.
if cerr.Permanent && m0.Attempts == 1 && dualstack && strings.HasPrefix(cerr.Secode, "7.") {
log.Debugx("change error type from permanent to transient", err, slog.Any("host", host), slog.Any("secode", cerr.Secode))
cerr.Permanent = false
}
// If server does not implement requiretls, respond with that code. ../rfc/8689:301
if errors.Is(cerr.Err, smtpclient.ErrRequireTLSUnsupported) {
cerr.Secode = smtp.SePol7MissingReqTLS30
metricRequireTLSUnsupported.WithLabelValues("norequiretls").Inc()
}
err = cerr
return cerr
}
return deliverResult{err: err}
return err
}

if err != nil {
return deliverResult{err: inspectError(err)}
}

// SMTP session is ready. Finally try to actually deliver.
Expand Down Expand Up @@ -695,7 +701,7 @@ func deliverHost(log mlog.Log, resolver dns.Resolver, dialer smtpclient.Dialer,
resps, err := sc.DeliverMultiple(ctx, mailFrom, rcpts, size, msg, has8bit, smtputf8, m0.RequireTLS != nil && *m0.RequireTLS)
if err != nil && len(resps) == len(msgResps) {
// If error and it applies to all recipients, return a single error.
return deliverResult{err: err}
return deliverResult{err: inspectError(err)}
}
var ntodo []*msgResp
for i, mr := range todo[:n] {
Expand Down

0 comments on commit feb8e6c

Please sign in to comment.