usememos/memos · error
SMTP server does not support STARTTLS
Error message
SMTP server does not support STARTTLS
What it means
Returned by Client's STARTTLS path (sendWithTLS in internal/email/client.go) when UseTLS is true but the server's EHLO response does not advertise the STARTTLS extension. The client refuses to send credentials and message body over a plaintext connection, so it aborts before authenticating.
Source
Thrown at internal/email/client.go:103
dialer := &net.Dialer{Timeout: smtpOperationTimeout}
conn, err := dialer.Dial("tcp", serverAddr)
if err != nil {
return errors.Wrapf(err, "failed to connect to SMTP server: %s", serverAddr)
}
defer conn.Close()
if err := conn.SetDeadline(time.Now().Add(smtpOperationTimeout)); err != nil {
return errors.Wrap(err, "failed to set SMTP connection deadline")
}
client, err := smtp.NewClient(conn, c.config.SMTPHost)
if err != nil {
return errors.Wrap(err, "failed to create SMTP client")
}
defer client.Quit()
if c.config.UseTLS {
if ok, _ := client.Extension("STARTTLS"); !ok {
return errors.New("SMTP server does not support STARTTLS")
}
if err := client.StartTLS(c.createTLSConfig()); err != nil {
return errors.Wrap(err, "failed to start SMTP STARTTLS")
}
}
return c.sendWithClient(client, auth, recipients, body)
}
// sendWithSSL sends email using SSL/TLS (port 465).
func (c *Client) sendWithSSL(auth smtp.Auth, recipients []string, body string) error {
serverAddr := c.config.GetServerAddress()
// Create TLS connection
tlsConfig := c.createTLSConfig()
dialer := &net.Dialer{Timeout: smtpOperationTimeout}
conn, err := tls.DialWithDialer(dialer, "tcp", serverAddr, tlsConfig)
if err != nil {View on GitHub (pinned to 14d757ce1f)
Solutions
- If the server is port 465 (implicit TLS), set UseSSL=true and UseTLS=false.
- If using port 587, confirm the server actually supports STARTTLS: openssl s_client -starttls smtp -connect host:587 or 'swaks -tls'.
- If the relay truly has no TLS, set UseTLS=false only over a trusted network (plaintext credentials otherwise).
- Check for middleboxes/proxies stripping EHLO extensions and use the TLS-capable port the provider documents.
Example fix
// before (465 with STARTTLS flag)
cfg := email.Config{SMTPHost: "smtp.example.com", SMTPPort: 465, UseTLS: true}
// after (465 uses implicit SSL)
cfg := email.Config{SMTPHost: "smtp.example.com", SMTPPort: 465, UseSSL: true} Defensive patterns
Strategy: validation
Validate before calling
// Go — pick the TLS mode from the port before sending
if cfg.SMTPPort == 465 {
cfg.UseSSL, cfg.UseTLS = true, false
}
if cfg.UseTLS {
// cheap capability probe avoids a wasted dial+auth attempt
conn, err := net.DialTimeout("tcp", cfg.GetServerAddress(), 5*time.Second)
if err == nil {
conn.Close()
}
} Try / catch
if err := client.Send(...); err != nil {
if strings.Contains(err.Error(), "STARTTLS") {
// either flip to UseSSL on 465, or pick a TLS-capable port; do NOT silently downgrade
return errors.Wrap(err, "SMTP TLS mismatch: use UseSSL for port 465 or a STARTTLS-capable port")
}
return err
} Prevention
- Map flags to ports: 587 => UseTLS, 465 => UseSSL, and never both.
- Verify with 'openssl s_client -starttls smtp -connect host:port' before deploying.
- Never fall back to plaintext automatically when STARTTLS is missing — treat it as a config error.
When it happens
Trigger: UseTLS=true against a server that only offers plaintext (port 25 relay without TLS) or that requires implicit TLS on 465; the EHLO extension list genuinely lacks STARTTLS. Also appears when a firewall/misconfigured proxy strips the extension or when the wrong port is used (465 expects SSL, not STARTTLS).
Common situations: Using UseTLS with port 465 instead of UseSSL; self-hosted relay (e.g., a local null client) with TLS disabled; corporate smarthost that only supports TLS on a different port; copy-pasted config mixing the STARTTLS and SSL flags.
Related errors
- SMTP host is required
- SMTP port must be between 1 and 65535
- from email is required
- notification email cannot enable both useTls and useSsl
- enabled notification email requires smtpHost, a positive smt
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/4e3fd586a1cf1602.
Report an issue: GitHub.