DMARC Engine
Home/Blog/RFC 8461: the MTA-STS standard explained
Blog

RFC 8461: the MTA-STS standard explained

A precise walk through RFC 8461: why server-to-server mail needed MTA-STS, the _mta-sts DNS signal, the HTTPS-hosted policy file, the none, testing and enforce modes, and exactly how a sending MTA fetches and applies a policy.

23 March 2026 · 13 min read

RFC 8461: the MTA-STS standard explained

RFC 8461, published by the IETF in September 2018, defines SMTP MTA Strict Transport Security, almost always shortened to MTA-STS. It exists to close a specific, decades-old hole in how mail servers talk to each other: the way one mail server discovers another, and the way they negotiate encryption, was never authenticated. MTA-STS does not invent new cryptography. It adds a published policy, anchored in the web's existing certificate trust, that lets a sending server insist on a verified, encrypted connection before it will hand over your mail.

This article walks through the standard itself: the DNS signal that announces a policy exists, the HTTPS-hosted policy file that carries the rules, the three enforcement modes, how a sending MTA actually fetches and applies a policy, and the failure behaviour that the RFC mandates. If you want to skip straight to checking a domain, the MTA-STS checker fetches and parses both the DNS record and the policy file for any domain. But understanding what it is checking will save you a lot of guesswork.

The problem RFC 8461 was written to solve

To appreciate MTA-STS, you have to understand how unprotected the default state of server-to-server mail really is.

When your server has a message for recipient@example.com, it looks up the MX records for example.com in DNS. Those records name the hosts that accept mail for the domain, in priority order. Your server connects to the highest-priority host on TCP port 25 and begins an SMTP conversation.

Encryption on that connection is provided by STARTTLS, an SMTP command the receiving server advertises to say "you may upgrade this plaintext session to TLS". The trouble is twofold, and RFC 8461 names both:

  • STARTTLS is opportunistic. If the receiving server does not advertise it, or if an active attacker strips the advertisement out of the SMTP banner, the sending server simply carries on in plaintext. There is no signal that says encryption was expected, so nothing to fall back from. This is a classic downgrade attack.
  • Certificates are not validated. Even when TLS is negotiated, the historical norm for SMTP was to accept any certificate, including self-signed and expired ones, and certificates that do not match the server name. So a man-in-the-middle can present its own certificate, terminate the TLS session, read everything, and forward it on. The encryption happens, but to the wrong party.

On top of all that, DNS MX lookups are usually unauthenticated. Without DNSSEC, an attacker positioned to tamper with DNS responses can point your sending server at a host they control. The whole discovery-and-encryption chain has no anchor of trust.

MTA-STS fixes the discovery and encryption parts of this by letting a domain publish a policy that says, in effect: "Mail for me must be delivered over TLS, with a valid certificate, to one of these named hosts. If you cannot do that, do not deliver." See the STARTTLS glossary entry for the underlying mechanism MTA-STS hardens, and the MTA-STS glossary entry for a one-paragraph summary.

A sister standard, DANE (RFC 7672), solves the same problem using DNSSEC and TLSA records instead of the web PKI. MTA-STS was designed to be deployable by operators who cannot deploy DNSSEC, which is why it leans on HTTPS and public certificate authorities rather than DNSSEC. The two can coexist; if you are weighing them, the DANE glossary entry covers the trade-offs.

The two-part architecture: a DNS signal and an HTTPS policy

The single most important structural fact about MTA-STS is that it splits into two pieces that live in two different places:

  1. A TXT record in DNS at _mta-sts.<domain>. This is a lightweight signal. It does not contain the policy. It only says "a policy exists, and here is its version identifier".
  2. A policy file served over HTTPS from https://mta-sts.<domain>/.well-known/mta-sts.txt. This is the actual policy: the mode, the permitted MX hosts, and a lifetime.

The reason for the split is deliberate and worth understanding, because it explains a lot of the standard's behaviour.

DNS, without DNSSEC, is not trustworthy. So MTA-STS does not put the security-critical rules in DNS. Instead, it puts the policy behind HTTPS, where the connection is authenticated by a certificate from a public CA. The DNS record's only job is to be a cheap, cacheable hint that tells a sender "go and fetch the policy", and to carry an id that changes whenever the policy changes, so senders know when to refetch. An attacker who tampers with the DNS record can, at worst, hide the existence of a policy or force a refetch; they cannot rewrite the policy itself, because the policy is fetched over an authenticated HTTPS channel from a fixed, well-known URL.

This is why a working MTA-STS deployment always needs both halves in place and in agreement. A common live failure is a DNS record that points at a policy file that returns a 404, which is exactly the situation covered in MTA-STS policy not found.

The DNS record in detail

The TXT record lives at the _mta-sts subdomain of the policy domain. For example.com:

_mta-sts.example.com.  IN  TXT  "v=STSv1; id=20260601000000Z"

It has exactly two defined fields:

  • v=STSv1 is the version tag and must come first. It is currently always STSv1. A sender that does not recognise the version ignores the record.
  • id=... is an opaque identifier, up to 32 alphanumeric characters. It has no meaning beyond "this string changes when the policy changes". A timestamp like 20260601000000Z is a common, readable convention, but any unique short token works.

The id is the mechanism by which senders detect a new policy. A sending MTA caches your policy. The next time it has mail for you, it checks the _mta-sts TXT record, and if the id differs from the one it cached, it knows to refetch the policy file from HTTPS. If the id is unchanged, it can trust its cached copy and skip the HTTPS round trip. This means every time you change your policy file, you must also bump the id, or senders will keep using their stale cached copy until it expires.

A few constraints the RFC imposes that catch people out:

  • There must be exactly one MTA-STS TXT record at _mta-sts. If a lookup returns multiple TXT records that parse as STS records, the result is undefined and senders may ignore the policy entirely. (This mirrors the "only one record" rule that bites people on SPF and DMARC.)
  • The record is a normal TXT record, so it benefits from a sane TTL. There is no requirement to use a particular TTL, but very low TTLs add lookup overhead and very high ones slow propagation of an id change.

You can confirm what a domain is publishing at this exact label with the DNS record checker, or use the dedicated MTA-STS checker which interprets it for you.

The policy file in detail

The policy file is plain text served over HTTPS. The URL is fixed by the standard and is not configurable:

https://mta-sts.example.com/.well-known/mta-sts.txt

Two things about that URL are load-bearing:

  • The host must be mta-sts.<your-domain>. You need a DNS record (A/AAAA or CNAME) for that hostname and a web server able to serve it over HTTPS with a valid certificate that matches mta-sts.example.com. The certificate validation here is the entire security model; a self-signed or mismatched certificate means the policy is rejected.
  • The path must be /.well-known/mta-sts.txt. The server must return it with Content-Type: text/plain and an HTTP 200.

The file is a set of key: value lines separated by CRLF. A typical enforced policy looks like this:

version: STSv1
mode: enforce
mx: mx1.example.com
mx: mx2.example.com
mx: *.mail.example.com
max_age: 604800

Field by field:

  • version: STSv1 must be the first line and mirrors the DNS version tag.
  • mode is one of enforce, testing or none. This is the field that decides what a sender actually does, and it is covered in its own section below.
  • mx lists the MX hostnames that are valid for this domain. There is one mx: line per pattern, and the policy may list several. A leading . wildcard matches exactly one label, so .mail.example.com matches a.mail.example.com but not mail.example.com or a.b.mail.example.com. These patterns must match the names presented in your MX records and on your servers' TLS certificates. If your MX is aspmx.l.google.com, that exact name (or a covering wildcard) has to appear here.
  • max_age is how long, in seconds, a sender may cache this policy, from 0 up to a maximum of 31557600 (one year). A week (604800) is a common starting point; longer ages give stronger protection against an attacker who can suppress your DNS record, because a cached enforce policy keeps protecting you even while the record is unreachable.

The combination of "fetched over authenticated HTTPS" and "lists the legitimate MX names" is what defeats the MX-substitution attack. Even if an attacker rewrites your MX records in an unauthenticated DNS response, a sender honouring your enforce policy will refuse to deliver to any host whose name is not in the policy's mx: list and whose certificate does not validate against it.

The three modes

mode is the heart of RFC 8461's operational design, because it lets you roll the standard out without risking mail loss.

mode: none

none means "I am declaring that I have no active MTA-STS policy." Its practical use is decommissioning. If you have published an enforce policy and want to withdraw it cleanly, you do not just delete the file; you publish a none policy (and bump the id) so that senders with a cached enforce policy fetch the none and stop enforcing. Pulling the file abruptly leaves senders enforcing a cached policy you can no longer see.

mode: testing

testing is the safe on-ramp, and skipping it is the single biggest mistake operators make. In testing mode, a sender evaluates your policy exactly as it would in enforce, but on failure it still delivers the mail anyway. The failure does not block delivery. Instead, if the sender supports TLS Reporting (TLSRPT, RFC 8460), it records the failure and reports it back to you.

The point of testing mode is to learn whether your policy is correct before it can cause an outage. You publish testing, you turn on TLSRPT, and you watch the reports for a week or two. If a major sender reports that it could not match your MX names, or could not validate your certificate, you fix that with zero impact on delivery, because testing mode never blocks anything. Set up TLSRPT alongside this; see the TLS-RPT glossary entry for the reporting record that makes testing mode useful.

mode: enforce

enforce is the protective mode. When a sender honours an enforce policy and cannot establish a TLS connection, with a valid CA-signed certificate, to a host whose name matches the policy's mx: patterns, the standard says it must not deliver the message to that host. It treats the situation as a temporary failure and the message queues for a later retry, rather than being delivered insecurely.

That last point is the whole reason testing mode exists. In enforce mode, a misconfiguration, an expired certificate, an MX name you forgot to list, does not silently degrade. It stops mail from reaching you. The progression none to testing to enforce is the safe path, and it is exactly the cautious, no-outage philosophy behind taking DMARC to enforcement as well.

How a sending MTA applies a policy, step by step

Putting the pieces together, here is the algorithm a compliant sending MTA follows, per RFC 8461, when it has mail for a domain:

  1. Resolve MX for the recipient domain as normal.
  2. Look up the _mta-sts TXT record. If there is no valid STS record, there is no MTA-STS policy in play; the sender proceeds with ordinary opportunistic STARTTLS. (This is why MTA-STS is purely additive and safe to ignore for non-participating domains.)
  3. Compare the id in the TXT record against any cached policy for this domain. If the sender has a non-expired cached policy with a matching id, it uses the cached policy and skips to step 5.
  4. Fetch the policy from https://mta-sts.<domain>/.well-known/mta-sts.txt over HTTPS, validating the certificate for mta-sts.<domain>. If the fetch or certificate validation fails and there is no usable cached policy, the sender has no policy to apply and falls back to opportunistic STARTTLS. Crucially, a failed policy fetch does not by itself block mail; a cached enforce policy still in its max_age does.
  5. Apply the cached or freshly fetched policy to the actual delivery attempt:
  6. - Check that the chosen MX host's name matches one of the policy's mx: patterns.
  7. - Open the connection, issue STARTTLS, and require the server's certificate to be valid and to match the MX host name.
  8. On success, deliver. On failure under enforce, do not deliver to that host; treat it as a transient error and retry later, possibly trying a lower-priority MX that also matches the policy.
  9. Under testing, deliver regardless, and emit a TLSRPT failure report if reporting is configured.

Two consequences of this algorithm are worth internalising. First, caching is doing real work: a sender that has already cached your enforce policy is protected against an attacker who later suppresses your DNS or policy file, for as long as max_age lasts. Second, the DNS record is only a trigger: tampering with it cannot weaken a cached enforce policy below its expiry, only delay the discovery of a new one.

How this fits with SPF, DKIM, DMARC and BIMI

MTA-STS is frequently lumped in with SPF, DKIM and DMARC, but it solves a different problem and it is worth being precise about the boundary.

  • SPF, DKIM and DMARC are about authenticity. They let a receiver decide whether a message genuinely came from your domain and what to do if it did not. They protect against spoofing and phishing of your domain. See the DMARC checker and the DMARC report analyzer for that side of the picture.
  • MTA-STS is about confidentiality and integrity in transit. It protects the connection over which mail is delivered to you, against passive snooping and active downgrade or interception. It says nothing about whether a message is authentic.

They are complementary, not alternatives. A domain at p=reject for DMARC with no MTA-STS still has its inbound mail deliverable over plaintext to an impostor server. A domain with enforce MTA-STS but no DMARC is still trivially spoofable. A complete email-authentication posture wants both, plus BIMI sitting on top of an enforced DMARC policy to add a verified brand logo. The full set of expected records is laid out on the requirements page.

One subtlety: MTA-STS protects inbound mail to your domain (you publish the policy; other people's servers honour it when sending to you). It does nothing for your outbound mail unless the recipient domains publish their own policies and your sending MTA honours them. Microsoft 365, Google Workspace and other large providers both publish and honour MTA-STS, which is why deploying it is increasingly table stakes for any domain that exchanges mail with them.

A realistic deployment plan

Pulling the standard into a concrete sequence:

  1. Stand up the policy host. Create mta-sts.example.com in DNS and serve /.well-known/mta-sts.txt over HTTPS with a valid certificate for that hostname.
  2. Publish a testing policy listing every MX name your domain genuinely uses, and set a modest max_age such as 86400 (one day) while you iterate.
  3. Publish the _mta-sts TXT record with a fresh id.
  4. Turn on TLSRPT so you receive failure reports, and watch them. Fix any MX or certificate mismatches the reports reveal.
  5. Promote to enforce once reports are clean, bump the id, and raise max_age to a week or more for stronger protection.
  6. Remember the id discipline: any change to the policy file requires a new id in the TXT record, or senders keep their stale cache.

Each of those steps has a way to go wrong, and most go wrong quietly: a CNAME that does not resolve, a certificate that covers example.com but not mta-sts.example.com, an MX name that drifted after a provider migration, or a policy file edited without bumping the id. The MTA-STS checker catches most of these in one pass, and MTA-STS policy not found walks through the most common 404 case.

The practical takeaway

RFC 8461 is, at its core, a small and elegant idea. DNS is untrustworthy, so use it only as a cacheable hint with a version id. Put the real, security-critical policy behind authenticated HTTPS at a fixed well-known URL. Give operators a testing mode so they can verify correctness before any failure can block mail, then let them flip to enforce to make TLS, with a valid certificate to a named MX host, mandatory. Use none to retire a policy cleanly. That is the whole standard.

The two failure modes to respect are these: forgetting to bump the id when you edit the policy, and jumping to enforce before testing has proven your MX names and certificates line up. Get those right and MTA-STS is a genuinely low-risk, high-value addition to a domain's email security.

When you are ready, check any domain's record and policy with the MTA-STS checker, read the step-by-step MTA-STS setup guide, and see how it sits within a full authentication stack on the requirements page. If you would rather not run the policy host, certificate and id discipline yourself, hosted MTA-STS sets it all up for you and takes the domain from testing to enforce without an outage, alongside hosted DMARC, SPF, DKIM and BIMI, with emailed monitoring and change alerts watching the records over time.

Share

See where your domain stands today

Run a free DMARC scan, then let us take you to enforced p=reject with no email outage.