How to publish MTA-STS

Three pieces have to line up: a DNS id record, a policy file over valid HTTPS, and an id you remember to bump.

Publishing MTA-STS is not one record but a small system of three moving parts that have to agree with each other. Miss any one and senders either never discover your policy or refuse to trust it. This is a practical walkthrough of each piece in the order you should build them, with the mistakes that catch people out at each step. Throughout, replace DOMAIN with your actual mail domain — the one that appears to the right of the @ in your addresses.

Piece one: the _mta-sts TXT id record

The first piece is a DNS TXT record that advertises "this domain has an MTA-STS policy, and here is its version." It lives at the host _mta-sts.DOMAIN and looks like this:

_mta-sts.DOMAIN. IN TXT "v=STSv1; id=20260706000000"

The id is the crucial field. It is an opaque version token — any string of up to 32 alphanumeric characters — and its only job is to change whenever your policy changes. A sending server fetches this TXT record, compares the id against the one it has cached, and only bothers to re-download the policy file if the id is different. The value has no meaning beyond "did this change?", so a timestamp such as 20260706000000 is a convenient, naturally increasing convention.

A common mistake here is putting the record at the wrong name. It must be the _mta-sts label of your mail domain, not mta-sts (no underscore, which is the web host) and not the bare domain. The underscore-prefixed name is what senders query, and it is a distinct thing from the policy host you will set up next.

Piece two: the policy file over valid HTTPS

The second piece is the policy itself, and this is where most of the real work is. It is a plain-text file that must be served at exactly this URL:

https://mta-sts.DOMAIN/.well-known/mta-sts.txt

Note the shape carefully. The host is mta-sts.DOMAIN — a real web host, with no underscore — and the path is /.well-known/mta-sts.txt. The contents look like this:

version: STSv1
mode: testing
mx: mx1.DOMAIN
mx: mx2.DOMAIN
max_age: 604800

Each directive is on its own line. version is always STSv1. mode is none, testing or enforce — start in testing. There is one mx line per MX host that is allowed to receive your mail, and a single leading wildcard is permitted (for example mx: *.DOMAIN) to cover a set of hosts under one label. max_age is the number of seconds a sender may cache the policy, from a few hundred up to 31557600 (a year); a settled policy commonly uses 604800 (one week).

The certificate has to be valid for the mta-sts host

The policy file is only trusted if it is served over HTTPS with a certificate that is valid for the hostname mta-sts.DOMAIN. This is the most frequently missed detail. It is not enough to have a valid certificate on your main website — the mta-sts subdomain needs its own coverage, whether that is a dedicated certificate or a wildcard that includes it. The certificate must be unexpired, chain to a public root, and match the hostname. A self-signed certificate, an expired one, or one issued only for www.DOMAIN will all cause senders to reject the policy. There must also be no HTTP redirect chain that lands off-host: the policy is fetched over HTTPS and redirects away from the mta-sts host are not honoured.

The Content-Type must be text/plain

The policy has to be returned with the header Content-Type: text/plain (a charset parameter such as text/plain; charset=utf-8 is fine). If your web host serves the .txt file as text/html, or as application/octet-stream because it treated it as a download, strict senders will not accept it. If you are generating the response from an application or a redirect rule rather than a static file, set the header explicitly. This one header is a surprisingly common cause of a policy that looks perfect but is quietly ignored.

Make the mx list match reality

The mx lines must correspond to your domain's actual MX records. If your DNS MX points at mx.provider.net but your policy lists only mail.DOMAIN, a sender following the policy will find that the host it is required to use is not the one it can deliver to — an mx mismatch — and under enforce that means failed delivery. List every MX that legitimately receives your mail, including secondary and backup MX hosts run by third parties, and confirm each one presents valid TLS. This is the single most consequential correctness check, which is why rolling out in testing first exists: it lets senders tell you about a mismatch before it can cost you mail.

Piece three: bump the id whenever you edit the policy

The third piece is a process, not a record. Every time you change the policy file — flip mode, add or remove an mx, change max_age — you must also change the id in the _mta-sts TXT record. Senders will not re-read the policy until they see a new id; they trust their cached copy until it expires. So an edit without an id bump is an edit that does not take effect for up to max_age seconds for every sender that already has your policy. Bump the id in the same maintenance window as the file edit and treat the two as a single atomic change. Because the id is just a change marker, incrementing a timestamp or a counter is all you need.

The whole thing, verified

Once the three pieces are in place — the _mta-sts TXT id, the policy file at the .well-known URL served as text/plain over a certificate valid for the mta-sts host, and a discipline of bumping the id — run the domain through the checker on the home page. It fetches the TXT record and the policy the way a real sender does, confirms the certificate and content type, and flags any mx mismatch. Pair it with STARTTLS Studio to confirm each MX's TLS handshake directly, publish a TLS-RPT record so you get failure reports, and see DNS Studio for the rest of the mail-authentication picture.


← Back to the MTA-STS checker