Between mail servers, TLS is usually opportunistic: the sender uses it when offered, but someone on the path can strip the STARTTLS offer and the mail then leaves unencrypted. MTA-STS (RFC 8461) lets a domain require senders to use TLS with a valid certificate, only to the listed MX hosts. TLS-RPT (RFC 8460) asks senders to report daily which TLS deliveries failed. Together they let you enforce TLS without learning about problems only when mail goes missing. Make the policy with the MTA-STS generator and read the reports with the TLS report analyzer.
What MTA-STS is made of
Three pieces, all needed (RFC 8461, section 3):
- The policy file, served over HTTPS at
https://mta-sts.example.com/.well-known/mta-sts.txt. - The
_mta-stsrecord, a TXT that announces the policy and gives it an id. - The name
mta-sts.example.com, with an address and a valid certificate, on the web server that serves the file.
version: STSv1
mode: testing
mx: mail.example.com
mx: *.backup.example.com
max_age: 604800
_mta-sts.example.com. IN TXT "v=STSv1; id=20260925120000Z"
Senders check the id in DNS and fetch the file only when the id changes. The id can be any string of 1–32 letters and digits (section 3.1); the date and time are a convenient choice.
The modes
| Mode | What senders do on a failure |
|---|---|
testing | report the failure (if you have TLS-RPT) and deliver anyway |
enforce | do not deliver to hosts without valid TLS or not listed |
none | treat the domain as having no policy |
In enforce, a sender that cannot deliver retries later and first checks whether a new policy appeared (section 5). An expired certificate does not lose mail on the spot, but delays it until you fix it.
The mx patterns
Every host in the MX record must match an mx: line and present a valid certificate for its name (section 4). A *. pattern covers exactly one level: *.example.com matches mail.example.com, but neither example.com nor a.b.example.com (section 4.1).
The usual mistake: a backup MX forgotten in the policy. Senders use it rarely, only when the first one does not answer, so the problem shows up exactly when you can least afford it (section 8.4).
Hosting the file
The server that serves the policy must (sections 3.2 and 3.3):
- have a valid HTTPS certificate for
mta-sts.example.com, not expired, from an authority senders trust; - answer 200 directly: senders do not follow redirects;
- serve the file as
text/plain, under 64 KB.
A file senders cannot fetch makes the domain count as having no MTA-STS, unless they already hold a valid policy in their cache (section 3.3).
max_age
max_age says how long senders keep the policy in cache, in seconds, at most 31557600 (one year). RFC 8461 expects weeks or more (section 3.2): a policy kept long cannot be bypassed by someone blocking its download. In testing, one day lets you correct quickly; in enforce, one to two weeks is a reasonable start.
TLS-RPT: the reports
TLS-RPT is a TXT record at _smtp._tls + domain, with where the reports go (RFC 8460, section 3):
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"
The destination can be an e-mail address or an https:// URL, or both, separated by a comma. Reports usually arrive once a day, as compressed JSON, and say which policy the sender applied, how many TLS sessions succeeded and why the others failed: no STARTTLS, an expired certificate, a wrong name, an invalid chain, a policy that could not be fetched (section 4.3). Reports sent by e-mail must be DKIM-signed by the reporting domain, and those without a signature must be ignored (section 3).
Moving to enforce, step by step
- Publish TLS-RPT and the policy in
testingmode, with amax_ageof one day. - Read the reports for a few weeks and fix what shows up: expired certificates, wrong names, MX hosts missing from the policy.
- When the reports show zero failures, move to
mode: enforceand raisemax_age.
On every change, put up the new file first, then the new id in _mta-sts (section 8.1). The other way round, a sender that sees the new id may fetch the old file and keep it in cache until the next change.
Dropping MTA-STS
Do not delete the record straight away: senders that hold the policy in cache keep applying it until it expires. Section 8.3 recommends: publish mode: none with a small max_age and a new id, wait for the old policy to expire from caches, and only then delete the record and the file.