I’m testing my instance and get no 250-STARTTLS offered.
V: 0.16.7
I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.
The most common cause of 250-STARTTLS not being advertised is that no TLS certificate is configured or resolvable for that listener. Stalwart only advertises STARTTLS when it can actually perform a TLS handshake; if the listener has no valid certificate, the extension is silently omitted (and a tls.not-configured error event is logged).
Here are the things to check, in order:
Certificate exists and is assigned. In the WebUI go to Settings › Network › Listeners, open your SMTP/submission listener, and confirm useTls is true (the default). Then check Settings › System Settings and confirm defaultCertificateId points to a valid certificate object.
A certificate object actually has a cert+key loaded. In the WebUI go to Settings › Network › TLS (or the Certificates section) and verify the certificate is present and not expired. If you are using ACME/Let’s Encrypt, confirm the ACME order completed successfully.
Implicit TLS confusion. If your listener has tlsImplicit: true, the connection is TLS from byte one and STARTTLS is intentionally not advertised in the EHLO response (it’s not needed). Port 465 should be tlsImplicit: true; port 587 and port 25 should be tlsImplicit: false (the default).
Check server logs for tls.not-configured. The docs describe this event as: “A TLS connection was requested but no certificate is configured for this listener.” If you see this in the logs, the root cause is a missing or mis-assigned certificate.
STARTTLS is advertised only when two things are true: the connection is not already inside TLS, and the listener has TLS enabled with a usable certificate. So the most likely cause is that TLS is not enabled on the listener you are testing, or no certificate is configured for it, so the listener came up as plain.
The other common case is testing an implicit-TLS port (465 or 993): there the session is already encrypted, so STARTTLS is intentionally not offered, which is correct.