exim.ro

MTA-STS and TLS-RPT: enforce TLS without losing mail

How to publish MTA-STS and TLS-RPT step by step: the policy file, the DNS records, hosting, testing mode, the TLS reports and moving to enforce.

Updated 5 min read9 sections

Run the MTA-STS generator

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):

  1. The policy file, served over HTTPS at https://mta-sts.example.com/.well-known/mta-sts.txt.
  2. The _mta-sts record, a TXT that announces the policy and gives it an id.
  3. 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

ModeWhat senders do on a failure
testingreport the failure (if you have TLS-RPT) and deliver anyway
enforcedo not deliver to hosts without valid TLS or not listed
nonetreat 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

  1. Publish TLS-RPT and the policy in testing mode, with a max_age of one day.
  2. Read the reports for a few weeks and fix what shows up: expired certificates, wrong names, MX hosts missing from the policy.
  3. When the reports show zero failures, move to mode: enforce and raise max_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.

Sources

  • RFC 8461: MTA-STS (discovery 3, MX validation 4, application 5, updates 8.1, removal 8.3)
  • RFC 8460: TLS-RPT (the record 3, the reports 4)