UnveilTech

UnveilScan Blog

← All articles

Try UnveilScan free

MTA-STS: the email TLS cousin nobody talks about

Posted 2026-04-29 · 5 min read · EMAILMTA-STS

DMARC, SPF and DKIM authenticate the sender. MTA-STS authenticates the transport. It's the policy that says "when delivering mail to example.com, you MUST use TLS, and you MUST validate the cert chain. If you can't, drop the message rather than fall back to plaintext."

Without MTA-STS, an attacker on the network path can downgrade the SMTP connection to plaintext (STRIPTLS attacks documented since 2015) and read every word. With MTA-STS, the sending MTA refuses to deliver in cleartext.

The two pieces

1. The DNS record

_mta-sts.example.com.  IN  TXT  "v=STSv1; id=20260429T120000;"

The id is opaque — it just has to change whenever you update the policy file. Convention: timestamp.

2. The policy file (HTTPS)

# Served at https://mta-sts.example.com/.well-known/mta-sts.txt
# Content-Type: text/plain
version: STSv1
mode: enforce
mx: mail.example.com
mx: *.googlemail.com
max_age: 604800
FieldMeaning
modeenforce (drop on TLS failure), testing (TLSRPT only), none (disabled)
mxAllowed MX targets. Wildcards OK. Sender's MX list MUST match.
max_ageHow long sender caches the policy (seconds). Recommended: 86400-604800.

The HTTPS-served policy file

The dependency on HTTPS for policy distribution is the catch. You need a separate subdomain mta-sts.example.com with a valid TLS cert. Most setups handle this by adding a virtual host in the same nginx/Apache that serves the apex.

# nginx
server {
    listen 443 ssl;
    server_name mta-sts.example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    location = /.well-known/mta-sts.txt {
        default_type text/plain;
        return 200 "version: STSv1\nmode: enforce\nmx: mail.example.com\nmax_age: 604800\n";
    }
    location / { return 404; }
}

Alternative: serve a static file at /var/www/mta-sts/.well-known/mta-sts.txt if you prefer file-based config.

The rollout dance (don't skip)

  1. Phase 1 (week 1-2): mode=testing. Receivers will report TLS failures via TLSRPT but will NOT drop messages. You watch the reports.
  2. Phase 2 (week 2+): mode=enforce. Receivers drop on TLS failure. Hardened.

Skipping testing mode and going straight to enforce is the classic gun-meets-foot mistake. If your MX hostname doesn't match the policy (typo, forgotten cert renewal, mid-migration) your mail just stops arriving. Receivers don't bounce — they queue and retry, then eventually drop. Customers think you're ignoring them.

TLSRPT (the companion record)

TLSRPT is the reporting half. Receivers send daily aggregate reports of TLS delivery failures to the address you publish:

_smtp._tls.example.com.  IN  TXT  "v=TLSRPTv1; rua=mailto:tls-reports@example.com"

You'll get JSON reports listing connection attempts, outcomes, error codes. Critical for the testing phase — you can't roll out enforce blind.

How UnveilScan checks MTA-STS

Our mta_sts_policy checker (Extended profile):

FindingSeverityTrigger
mta_sts_missingLOWNo MTA-STS record at all
mta_sts_mode_noneLOWPolicy exists but mode=none
mta_sts_mode_testingINFOPolicy in testing mode (transitional)
mta_sts_mx_mismatchHIGHPolicy mx doesn't match DNS MX (silent breakage risk)
mta_sts_unreachableMEDIUMPolicy URL returns 404/500/timeout
Why the slow adoption. MTA-STS is real work. You need a separate subdomain, an HTTPS server for it, a static file, two DNS records, plus the testing rollout. None of this is hard but every step is a moving part. Most domain admins skip it, accepting the residual STARTTLS-strip risk. Their loss.

Check your email transport policy

Extended scan reports MTA-STS + TLSRPT presence and policy alignment.

See pricing