Why it matters
The point of MTA-STS is to stop active downgrade attacks on inbound SMTP, a man-in-the-middle stripping STARTTLS or spoofing your MX so mail is delivered in cleartext or to an attacker's server. With the policy file unreachable, sending MTAs silently fall back to opportunistic TLS, which offers no such protection, so you gain none of the security you appear to have advertised. The dangerous part is the false sense of security: dashboards and DMARC/BIMI checklists show "MTA-STS present," but real senders enforce nothing. Note this rarely blocks legitimate mail - delivery continues over opportunistic TLS - so the failure is invisible unless you also run TLS-RPT, which is exactly why it goes unnoticed. This is governed by RFC 8461 (SMTP MTA Strict Transport Security).
Common causes
- The `_mta-sts` TXT record was added, but the `mta-sts.<domain>` policy host was never provisioned: no A/AAAA/CNAME record, or no web server answering on port 443.
- The file is served at the wrong location, missing the `.well-known/` prefix, a typo/wrong case in `mta-sts.txt`, or on the apex/`www` host instead of the `mta-sts.` subdomain.
- The TLS certificate on `mta-sts.<domain>` is expired, self-signed, name-mismatched, or missing intermediates; RFC 8461 requires a non-expired cert valid for the `mta-sts` DNS-ID chaining to a trusted root, so any cert error makes the policy unfetchable.
- The endpoint returns a 3xx redirect (e.g. redirecting `mta-sts.example.com` to `www.example.com` or forcing a path change), RFC 8461 says redirects MUST NOT be followed; only a direct HTTP 200 is valid.
- The web server returns the file with a non-200 status (404/403/500), or with the wrong media type, senders SHOULD validate that the media type is `text/plain`, so a non-text type can cause the policy to be rejected.
- The policy file body is malformed or incomplete - missing `mode`, missing `max_age`, wrong `version`, or CRLF/encoding issues - so it parses as invalid and is treated as no policy.
- A CNAME to a static host or CDN (GitHub Pages, Cloudflare Worker/Pages, S3) that isn't fully provisioned for the custom hostname, so the HTTPS fetch fails even though DNS resolves.
- The `id` in the TXT record was bumped but the file was never deployed/updated, or a firewall/geo-rule blocks the crawler's HTTPS request to the policy host.
How to fix MTA-STS Not Enforced
- Confirm the advertisement: `dig +short TXT _mta-sts.example.com` should return exactly one record like `v=STSv1; id=20240101T120000Z;` (id is 1-32 alphanumeric characters). Note the id value.
- Provision the policy host: create a DNS record for `mta-sts.example.com` (A/AAAA or CNAME) pointing to a TLS-capable endpoint, and issue a valid, non-expired certificate for the hostname `mta-sts.example.com` (e.g. Let's Encrypt) with a complete chain and correct SAN.
- Publish the file at exactly `https://mta-sts.example.com/.well-known/mta-sts.txt`, served with HTTP 200, `Content-Type: text/plain`, and NO redirect (do not 301/302 to another host or path).
- Write correct contents, starting in testing mode: version: STSv1 mode: testing mx: mail.example.com mx: *.example.net max_age: 86400 Every required field (version, mode, mx, max_age) must be present; max_age is non-negative integer seconds with a maximum of 31557600 (~1 year).
- Make the `mx:` patterns match your live MX exactly, run `dig +short MX example.com`, list every MX hostname, and use a wildcard (`*.example.net`) only where the entire leftmost label varies (`*.example.net` matches `mail.example.net` but not `example.net` or `a.b.example.net`).
- Verify the fetch end-to-end: `curl -sSv https://mta-sts.example.com/.well-known/mta-sts.txt`: confirm HTTP 200, `text/plain`, valid TLS (no cert warnings), no redirect, and the exact policy body.
- Enable TLS-RPT so failures become visible: add a TXT record at `_smtp._tls.example.com` like `v=TLSRPTv1; rua=mailto:[email protected];`, then watch the reports for successful policy application.
- Once testing mode reports clean policy fetches and TLS success from real senders, change `mode: testing` to `mode: enforce` in the file, and bump the `id` in the `_mta-sts` TXT record (e.g. a new timestamp) so caching senders re-fetch the updated policy.
- Re-validate with an external checker (Hardenize, MXToolbox, or an MTA-STS-specific validator) and, going forward, bump the TXT `id` every time you edit the policy file and monitor certificate expiry on the `mta-sts.` host.
Frequently asked questions
Is my mail bouncing because the policy file is missing?
Almost certainly not. When a sender sees the TXT record but can't fetch a valid policy and has no cached one, RFC 8461 requires it to deliver as if MTA-STS were not implemented, using opportunistic TLS. So mail keeps flowing; you just get zero downgrade protection. The record is effectively inert until the file is reachable.
Why do I need both a DNS record and an HTTPS file?
They do different jobs. The DNS TXT record is cheap and cacheable and only signals that a policy exists plus a version `id`, so senders know when to re-fetch. The actual, authoritative policy is fetched over HTTPS so it's authenticated by web PKI (a valid TLS cert on the `mta-sts.` host) rather than by DNS, that's what makes it resistant to DNS spoofing without requiring DNSSEC.
Can I just redirect mta-sts.example.com to my main website?
No. RFC 8461 explicitly forbids following 3xx redirects when fetching the policy; only a direct HTTP 200 response at `/.well-known/mta-sts.txt` is valid. A redirect is one of the most common reasons a published record ends up not enforced. Serve the file directly on the `mta-sts.` host.
Should I go straight to enforce mode?
Start with `mode: testing`. In testing, senders still deliver even when TLS validation fails but report the failures via TLS-RPT, letting you catch a wrong MX list or cert issue safely. Only switch to `mode: enforce` - where senders refuse to deliver to non-compliant MX - after you've confirmed clean reports, and bump the TXT `id` so it takes effect.