What it is
SMTP between mail servers uses STARTTLS opportunistically: if encryption fails or an attacker strips the STARTTLS offer, the message is delivered in plain text anyway. MTA-STS (RFC 8461) lets a domain declare that mail for it must be delivered over TLS, with a valid certificate, to a listed set of MX hosts. It has two parts: a TXT record that announces the policy and its version, and a policy file served over HTTPS.
_mta-sts.example.com. 3600 IN TXT "v=STSv1; id=20261005T120000"
The policy file must be at exactly https://mta-sts.example.com/.well-known/mta-sts.txt:
version: STSv1
mode: enforce
mx: mail.example.com
mx: *.mail.protection.outlook.com
max_age: 604800
The fields
| Where | Field | Meaning |
|---|---|---|
| TXT | v=STSv1 |
Version, first in the record |
| TXT | id= |
1-32 letters and digits; change it whenever the policy file changes |
| File | mode |
testing (report failures, deliver anyway), enforce (don't deliver without valid TLS to a listed MX), none (policy withdrawn) |
| File | mx |
One line per allowed MX host; *.example.net matches one leftmost label |
| File | max_age |
Seconds a sender may cache the policy, up to 31557600 (about a year) |
Sending servers fetch the file over HTTPS (the certificate for mta-sts.example.com must be valid, and redirects are not followed), cache it for max_age, and only re-fetch when the TXT id changes or the cache expires. That caching is what defeats a downgrade attack: an attacker can't remove a policy that's already cached.
Common setups
- Hosting the file: any static host with HTTPS on the
mta-stssubdomain works, such as GitHub Pages, Cloudflare Pages or a Worker, or your own web server. Serve it astext/plain. - Google Workspace:
mx: aspmx.l.google.comandmx: *.aspmx.l.google.com(the wildcard doesn't match the bare name). - Microsoft 365:
mx: *.mail.protection.outlook.com. - TLS reporting: add TLS-RPT (RFC 8460) so senders tell you about failures:
_smtp._tls.example.com TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com".
Start in testing with a short max_age such as 86400, read the TLS reports for a couple of weeks, then switch to enforce with a week or more.
How to check it
The MTA-STS checker reads the TXT record, fetches the policy file and compares its mx lines to your real MX records, and also looks at TLS-RPT and BIMI. From a terminal:
dig +short TXT _mta-sts.example.com
nslookup -type=TXT _mta-sts.example.com
curl https://mta-sts.example.com/.well-known/mta-sts.txt
Common mistakes
- Changing the file but not the
id: senders keep the old policy untilmax_ageruns out. - An MX not listed in the policy, for example after a provider migration. In
enforcemode mail to that host is refused, so update the policy and theidbefore switching MX. - No HTTPS certificate for
mta-sts.<domain>or a redirect to another URL: the policy can't be fetched. - Removing MTA-STS abruptly. Publish
mode: nonewith a newidand keep it up for longer than the oldmax_agebefore deleting anything. - Expecting it to protect outgoing mail: MTA-STS protects mail sent to your domain by senders that support it.
Related record types
- MX record: the hosts the policy must list.
- TXT record: the record type that carries
_mta-sts. - DMARC record and BIMI record: other mail-domain policies.