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

85 lines
2.8 KiB
Markdown

# 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):
```bash
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
```bash
# 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:
```bash
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.