fix: use WithTLSPolicy instead of WithTLSPortPolicy to preserve user-configured SMTP port

WithTLSPortPolicy calls SetTLSPortPolicy, which checks `c.port == DefaultPort`
(25) to decide whether the port was explicitly set or left as default. When a
user configures port 25 — common for internal relay hosts that accept plaintext
SMTP — the guard condition evaluates true and the library silently overrides the
port to 587 (DefaultPortTLS) with a fallback to 25.

This causes a two-stage failure in environments where port 587 is unreachable:

  1. The primary dial to host:587 blocks for the full 15-second connection
     timeout (go-mail DefaultTimeout) waiting on a firewalled port.
  2. The fallback dial to host:25 fires with an already-expired context,
     producing a misleading "lookup <host>: i/o timeout" DNS error rather
     than the actual root cause (port 587 unreachable).

The previous mail library (gopkg.in/mail.v2) used the port value directly
without any policy-based override, so this regression surfaced only after
migrating to github.com/wneessen/go-mail.

WithTLSPolicy applies the same STARTTLS negotiation semantics (NoTLS or
TLSOpportunistic) without mutating the port, which is the correct choice
when the caller has already provided an explicit port via WithPort.
This commit is contained in:
Ompragash Viswanathan
2026-02-17 19:30:07 +05:30
parent b4bc696ee8
commit 5b0a93b192
+5 -2
View File
@@ -185,10 +185,13 @@ func (p Plugin) Exec() error {
}
// Handle STARTTLS policy
// Note: Use WithTLSPolicy (not WithTLSPortPolicy) to avoid overriding
// the user-configured port. WithTLSPortPolicy treats port 25 as "default/unset"
// and silently changes it to 587 for TLSOpportunistic/TLSMandatory.
if p.Config.NoStartTLS {
options = append(options, mail.WithTLSPortPolicy(mail.NoTLS))
options = append(options, mail.WithTLSPolicy(mail.NoTLS))
} else {
options = append(options, mail.WithTLSPortPolicy(mail.TLSOpportunistic))
options = append(options, mail.WithTLSPolicy(mail.TLSOpportunistic))
}
client, err := mail.NewClient(p.Config.Host, options...)