fix(email): set EHLO hostname for SMTP relay compatibility (#3679)

This commit is contained in:
Arnaud Dezandee
2026-06-04 08:07:47 +02:00
committed by GitHub
parent 49c913a4fa
commit a9f0739b52

View File

@@ -31,6 +31,7 @@ type EmailService struct {
smtpPassword string
smtpTLSInsecure bool
smtpTLSImplicit bool
smtpEHLOName string
}
func NewEmailService() *EmailService {
@@ -49,6 +50,14 @@ func NewEmailService() *EmailService {
smtpPassword := os.Getenv("SMTP_PASSWORD")
smtpTLSInsecure := os.Getenv("SMTP_TLS_INSECURE") == "true"
// EHLO/HELO name. net/smtp defaults to "localhost", which strict relays
// (e.g. smtp-relay.gmail.com) reject from a public source. Fall back to the
// machine hostname when SMTP_EHLO_NAME is unset.
smtpEHLOName := strings.TrimSpace(os.Getenv("SMTP_EHLO_NAME"))
if smtpEHLOName == "" {
smtpEHLOName, _ = os.Hostname()
}
// SMTP_TLS=implicit forces an immediate TLS handshake on connect (SMTPS).
// Required by providers like Aliyun enterprise mail that only offer port 465
// SSL and do not advertise STARTTLS. Default (empty / "starttls") preserves
@@ -89,6 +98,7 @@ func NewEmailService() *EmailService {
smtpPassword: smtpPassword,
smtpTLSInsecure: smtpTLSInsecure,
smtpTLSImplicit: smtpTLSImplicit,
smtpEHLOName: smtpEHLOName,
}
}
@@ -129,6 +139,15 @@ func (s *EmailService) sendSMTP(to, subject, htmlBody string) error {
}
defer c.Close()
// Greet with a real hostname before any other command, else net/smtp lazily
// EHLOs "localhost" — which strict relays drop, surfacing as an opaque EOF on
// a later command rather than at the EHLO itself.
if s.smtpEHLOName != "" {
if err = c.Hello(s.smtpEHLOName); err != nil {
return fmt.Errorf("smtp EHLO %s: %w", s.smtpEHLOName, err)
}
}
// STARTTLS upgrade only makes sense when the underlying connection is still
// plaintext. Skip when we already dialed with implicit TLS.
if !s.smtpTLSImplicit {