Skip to content

Encryption of mail sent to you can be quietly switched off

Warning Whole domain E-mail delivery

General instructions. Open this article from your PageCheck report to see it filled in with your domain's mail servers and your DNS host's exact steps.

What it is

Mail between servers is usually encrypted, but only if both sides agree to it on the way, and an attacker in between can remove that offer: the mail is then delivered unencrypted and nobody notices. MTA-STS is a small public policy that tells sending servers your mail servers always support encryption, so they must not deliver without it.

What is wrong

example.com has no MTA-STS policy, so encryption of mail sent to it can be quietly switched off. Its DMARC policy already stops mail forged in its name; this is the next step.

How to fix

Start in testing mode: senders then only report problems and still deliver every message, so nothing can go wrong while you check the set-up.

1. Write the policy file. Save this as a plain text file named mta-sts.txt. It must list every mail server (MX) of the domain:

mta-sts.txt

version: STSv1
mode: testing
mx: mail.example.com
max_age: 86400

2. Publish it on its own address. The file must open at https://mta-sts.example.com/.well-known/mta-sts.txt over HTTPS with a valid certificate and without any redirect — a redirect to www or to the main site makes senders ignore it.

If your DNS is at Cloudflare, the simplest place is a Cloudflare Worker (free): Workers & Pages → Create → Create Worker, name it mta-sts, replace its code with the code below and Deploy. Then the Worker's Settings → Domains & Routes → Add → Custom domain: mta-sts.example.com. Cloudflare creates the DNS record and the certificate for it.

Cloudflare Worker

export default {
  async fetch() {
    const policy = [
      'version: STSv1',
      'mode: testing',
      'mx: mail.example.com',
      'max_age: 86400',
    ].join('\r\n') + '\r\n';
    return new Response(policy, { headers: { 'content-type': 'text/plain; charset=utf-8' } });
  },
};

On your web host: add the subdomain mta-sts.example.com with an SSL certificate, create a folder named .well-known in it and upload mta-sts.txt there.

  • Plesk: Websites & Domains → Add Subdomain, then SSL/TLS Certificates → Let's Encrypt, then File Manager.
  • cPanel: Domains → Create A New Domain, then SSL/TLS Status → Run AutoSSL, then File Manager.

3. Announce the policy in DNS.

  • Open the DNS records of your domain where its DNS is managed: usually the domain registrar, the web host or Cloudflare.
  • Add a TXT record with the name _mta-sts and the value v=STSv1; id=1, and save.

4. Ask for reports. Sending servers then e-mail a daily report of any encrypted delivery that failed. Create the mailbox tls-reports@example.com first (or use another address you read).

  • Open the DNS records of your domain where its DNS is managed: usually the domain registrar, the web host or Cloudflare.
  • Add a TXT record with the name _smtp._tls and the value v=TLSRPTv1; rua=mailto:tls-reports@example.com, and save.

5. Check it. Open https://mta-sts.example.com/.well-known/mta-sts.txt: it should show the file as plain text. Then run this check again: it reads the file and compares its mx lines with your mail servers.

6. About two weeks later: enforce it. When the reports show no failed deliveries, change the file to enforce mode and a one-week max_age:

mta-sts.txt

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

Then change the _mta-sts TXT record to v=STSv1; id=2, so senders fetch the new file. Every later change to the file needs a new id, and when your mail servers change, update the mx lines first.

Set up MTA-STS (RFC 8461) for the mail domain example.com, starting in testing mode, and TLS-RPT (RFC 8460) reporting.
Its MX hosts (look them up first; this is a placeholder): mail.example.com.

Steps:
1. Serve this policy at https://mta-sts.example.com/.well-known/mta-sts.txt over HTTPS with a valid certificate for mta-sts.example.com, status 200, Content-Type text/plain, no redirect:
   version: STSv1
   mode: testing
   mx: mail.example.com
   max_age: 86400
   Use the web host (a subdomain with its own certificate) or a static host.
2. Add the TXT record _mta-sts.example.com = "v=STSv1; id=1".
3. Add the TXT record _smtp._tls.example.com = "v=TLSRPTv1; rua=mailto:tls-reports@example.com" (make sure that mailbox exists).
4. Verify: curl -sv https://mta-sts.example.com/.well-known/mta-sts.txt (200, no redirect, the policy text) and dig TXT _mta-sts.example.com +short.
5. Tell me to come back in two weeks: if the TLS reports show no failures, switch to mode: enforce with max_age: 604800 and change the TXT record to "v=STSv1; id=2".
Every mx line must match an MX host exactly or by a one-label wildcard (*.example.com); a missing one makes enforcing senders refuse mail.

Resources:
- MTA-STS, RFC 8461 (IETF): https://datatracker.ietf.org/doc/html/rfc8461
- TLS-RPT, RFC 8460 (IETF): https://datatracker.ietf.org/doc/html/rfc8460

Check your site to see whether it has this problem. Check a website