majorwiki/05-troubleshooting/networking/postfix-sendgrid-tls-handshake-failure.md
majorlinux 52ca8a0413 wiki: batch update — 4 new articles + 4 updates
New articles:
- Postfix SendGrid TLS handshake failure (port 465 vs 587)
- Plex transcoding troubleshooting
- Ansible Ubuntu reboot detection kernel mismatch
- WSL2 PyTorch checkpoint Windows filesystem deadlock

Updated:
- AWS S3 cost management (expanded)
- Network overview (IP updates)
- HEVC VAAPI batch encode (progress + fixes)
- SUMMARY.md (new entries)
2026-05-25 13:55:10 -04:00

2.8 KiB

Postfix + SendGrid: TLS Handshake Failure (Port 465 vs 587)

Symptom

Outbound mail silently queues with no delivery. postqueue -p shows deferred messages:

(Cannot start TLS: handshake failure)

/var/log/maillog shows:

SSL_connect error to smtp.sendgrid.net[...]:465: -1
warning: TLS library problem: error:0A00010B:SSL routines::wrong version number

Or on port 587:

warning: TLS library problem: error:0A0000C1:SSL routines::no shared cipher

Root Cause

Port 465 (SMTPS) uses implicit TLS — the connection starts encrypted immediately. Port 587 (submission) uses STARTTLS — the connection starts plaintext, then upgrades.

Postfix has two settings that must match the port:

Port smtp_tls_wrappermode smtp_tls_security_level
465 yes encrypt
587 no encrypt (or may)

If smtp_tls_wrappermode=yes is set with port 587, Postfix sends a TLS ClientHello immediately but the server expects a plaintext SMTP greeting first — wrong version number.

If smtp_tls_wrappermode=no is set with port 465, Postfix sends a plaintext EHLO but the server expects a TLS ClientHello — no shared cipher or connection reset.

Fix

Use port 587 + STARTTLS (recommended — more widely supported and debuggable):

postconf -e 'relayhost = [smtp.sendgrid.net]:587'
postconf -e 'smtp_tls_wrappermode = no'
postconf -e 'smtp_tls_security_level = encrypt'
systemctl restart postfix
postqueue -f   # flush stuck messages

Verify

# Check config
postconf relayhost smtp_tls_wrappermode smtp_tls_security_level

# Test TLS connection manually
openssl s_client -starttls smtp -connect smtp.sendgrid.net:587 -brief

# Watch delivery
tail -f /var/log/maillog | grep status=

Successful delivery looks like:

Untrusted TLS connection established to smtp.sendgrid.net[...]:587: TLSv1.3 with cipher TLS_AES_128_GCM_SHA256
status=sent (250 Ok: queued as ...)

Why "Untrusted"?

If smtp_tls_CAfile and smtp_tls_CApath are both empty, Postfix can't verify the server certificate and logs "Untrusted TLS connection." The connection is still encrypted — just not authenticated. To fix, point to the system CA bundle:

postconf -e 'smtp_tls_CAfile = /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem'  # Fedora
# or
postconf -e 'smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt'  # Ubuntu/Debian

Notes

  • OpenSSL 3.x is stricter about protocol mismatches than OpenSSL 1.1 — a config that worked on older distros may break after an OS upgrade.
  • SendGrid supports both ports, but port 587 + STARTTLS is the documented recommendation.
  • This applies to any SMTP relay (Mailgun, AWS SES, etc.), not just SendGrid — the port/wrappermode pairing is universal.