RE:NODE

App hosting11 min read

MTA-STS, DANE and TLS-RPT: enforcing TLS for email

Why STARTTLS between mail servers can be stripped, and how MTA-STS, DANE and TLS-RPT make encrypted delivery to your domain mandatory and measurable.

0 readers

Mail between servers is usually encrypted, but nothing guarantees it. The sending server connects to your MX on port 25, sees STARTTLS offered, and upgrades - unless something in the path removes that offer, in which case it shrugs and sends in plain text. It also does not check that the certificate it is shown belongs to your server. That is opportunistic TLS: it stops passive eavesdropping and nothing else. Three standards close the gap. MTA-STS publishes a policy over HTTPS that says "my mail servers are these names, and they always do valid TLS". DANE publishes the certificate's fingerprint in DNSSEC-signed DNS. TLS-RPT asks senders to report back when TLS to you fails. For most domains the right first step is TLS-RPT plus MTA-STS in testing mode, moving to enforce after a few weeks of clean reports; DANE is worth it if your DNS host does DNSSEC properly.

How STARTTLS works between mail servers, and where it fails#

An SMTP session between two servers starts in plain text. The receiving server lists its capabilities in reply to EHLO, and if STARTTLS is among them, the sender can ask to upgrade:

code
S: 220 mail.example.com ESMTPC: EHLO mx.sender.netS: 250-mail.example.comS: 250-SIZE 52428800S: 250-STARTTLSS: 250 ENHANCEDSTATUSCODESC: STARTTLSS: 220 2.0.0 Ready to start TLS

Everything after that is encrypted. The weaknesses are in the two decisions the sender makes:

  • Whether to upgrade. The capability list travels in plain text. An attacker in the path - or a badly behaved firewall that "inspects" SMTP, which is a real thing - can strip the 250-STARTTLS line. The sender sees a server that does not offer TLS and delivers in clear text, because refusing would mean refusing mail to the large number of servers that genuinely do not support it.
  • Whether to trust the certificate. Even with TLS, the sender has no reliable way to know which name the certificate should carry. The MX record came from unauthenticated DNS, so an attacker who can forge DNS can point the sender at their own server with their own valid certificate. Most senders therefore accept any certificate, self-signed and expired ones included.

Opportunistic TLS is still worth having - it defeats bulk passive collection - but it does nothing against an active attacker. MTA-STS and DANE each solve both problems, by giving the sender an authenticated statement, published in advance, of what to expect.

MTA-STS: a policy published over HTTPS#

MTA-STS (RFC 8461) has two parts: a DNS TXT record that says a policy exists, and the policy itself, fetched over HTTPS from a fixed address. Because HTTPS uses the ordinary web certificate system, the policy is authenticated even though the DNS lookup is not.

policy idfetch and cacheTLS, cert checkedfailures and successesSending serverDNS TXT_mta-sts.example.comHTTPS policymta-sts.example.comYour MXmail.example.com:25TLS-RPT reportdaily JSON
How a sender applies your MTA-STS policy

The sender looks up _mta-sts.example.com, finds an id, fetches https://mta-sts.example.com/.well-known/mta-sts.txt, and caches the policy for max_age seconds. From then on, every delivery to your domain must go to an MX host matching the policy, over TLS, with a certificate that is valid for that host name and chains to a public certificate authority. In enforce mode a sender that cannot meet those conditions does not deliver; the message waits in its queue and is retried.

The cache is what makes it resistant to attack. An attacker who blocks the policy fetch on a later delivery achieves nothing, because the sender still has the policy from last time. The first contact is the weak moment, which is why max_age is normally long.

Publishing an MTA-STS policy#

Three things are needed: the policy file, a web server that serves it with a valid certificate at mta-sts.<your domain>, and the TXT record.

The policy file:

.well-known/mta-sts.txt
version: STSv1mode: testingmx: mail.example.commax_age: 86400
KeyValuesWhat it means
versionSTSv1The only version
modetesting, enforce, noneReport only, require, or withdraw the policy
mxA host name, or *.example.comRepeat the line for each MX host
max_ageSeconds, up to 31557600How long senders cache the policy

The TXT record:

TXT record at _mta-sts.example.com
v=STSv1; id=20261008T120000

The id is any string of up to 32 letters and digits. Senders compare it with the one they cached, and refetch the policy when it changes, so a timestamp is the convenient choice. Every time you edit the policy file, change the id.

Rules that the specification makes strict, and which account for most broken deployments:

  1. The policy host must have a valid certificate for mta-sts.example.com, issued by a public authority. Self-signed will not do; this is the whole basis of trust.
  2. No redirects. Senders must not follow an HTTP redirect when fetching the policy. A web server that redirects /.well-known/... to another path or host breaks MTA-STS silently.
  3. Serve it as `text/plain` with a 200 response.
  4. Every `mx` line must match the names in your MX records, and the certificate on each mail server must be valid for the name the MX points at.

Start with mode: testing and a short max_age such as a day. In testing mode senders deliver whatever happens, but report failures through TLS-RPT. After two or three weeks of reports showing nothing but successes, switch to enforce, raise max_age to a week or more (604800), and change the id.

TLS-RPT: finding out when TLS fails#

TLS-RPT (RFC 8460) is one more TXT record. It asks senders to send you a daily summary of their TLS connections to your domain:

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

Large senders, including Google and Microsoft, send these reports. Each is a gzipped JSON document covering one day: the policy they applied (MTA-STS, DANE or none), counts of successful sessions, and counts of failures by type. The failure types are specific enough to act on:

Result typeUsual cause
starttls-not-supportedThe server did not offer STARTTLS, or something stripped it
certificate-expiredRenewal failed
certificate-host-mismatchCertificate does not cover the MX name
validation-failureChain incomplete or not trusted
sts-policy-fetch-errorThe policy URL failed, redirected or has a bad certificate
sts-webpki-invalidThe policy host's certificate is invalid
tlsa-invalid / dane-requiredDANE record wrong or unusable

Publish TLS-RPT before anything else, even without MTA-STS. With no policy, the reports still tell you how many senders reached you over TLS, which is a useful baseline, and they cost nothing. Use a dedicated mailbox for them - they arrive daily from every large provider - and either read the JSON or feed it into one of the free report viewers.

DANE: certificates pinned in DNSSEC#

DANE for SMTP (RFC 7672) takes a different route to the same goal. Instead of an HTTPS policy, you publish a TLSA record that states which certificate or key your mail server presents, and the record is trusted because the zone is signed with DNSSEC.

TLSA record for mail.example.com
_25._tcp.mail.example.com. 3600 IN TLSA 3 1 1 (    8d02536c887482bc34ff54e41d2ba659bf85b341a0a20afadb5813dcfbcf286d )

The three numbers are usage, selector and matching type. 3 1 1 - "this exact end-entity key, by its SHA-256 hash" - is the common and recommended form for mail: it does not depend on any certificate authority at all, and a self-signed certificate is acceptable. The hash is of the certificate's public key, which you can compute from the certificate file:

bash
$ openssl x509 -in cert.pem -noout -pubkey \    | openssl pkey -pubin -outform DER \    | openssl dgst -sha256

DANE has two hard requirements, and they decide whether it is for you:

  • The zone holding your `MX` host names must be DNSSEC-signed, and so must the zone of your domain for the MX lookup to be trusted. If your DNS host does not offer DNSSEC, or you are not confident managing it, stop here. A broken DNSSEC chain does worse than disable DANE - validating resolvers stop resolving the domain at all.
  • Key rollover has to be planned. Because the record pins the key, renewing the certificate with a new key without updating the record first makes every DANE-validating sender refuse delivery. Either reuse the key on renewal (most ACME clients have an option for it), or publish the new key's hash alongside the old one, wait out the record's TTL, then switch the certificate and remove the old hash.

DANE is validated by Postfix and Exim when configured to, by Stalwart for outbound mail, and by Microsoft's Exchange Online, among others. Gmail relies on MTA-STS instead. That split is why many operators publish both.

MTA-STS or DANE

MTA-STSDANE
Trust comes fromPublic web certificatesDNSSEC
NeedsA web host for the policyA DNSSEC-signed zone
First contact protectedNo, relies on cachingYes
CertificateMust be publicly trustedAny, including self-signed
Honoured byGoogle, Microsoft and othersMicrosoft, many self-hosted servers
Main failure modePolicy host or certificate breaksKey changed without the record

If you can only do one, MTA-STS is the easier and more widely honoured choice for a small domain. If your DNS host makes DNSSEC a checkbox and you are disciplined about key rollover, add DANE. They coexist without conflict, and TLS-RPT reports on both.

The sending side: your server and other domains#

Everything above protects mail sent to you. Your own server, when it sends, makes the same decisions about other domains. Stalwart checks MTA-STS policies and DANE records when delivering outbound mail, and both are configurable per delivery strategy in the web admin. The defaults treat them as optional: a policy that is published and valid is applied, but a domain whose policy cannot be fetched or validated still receives mail. Setting either to "require" globally would make your server refuse delivery to the many domains that publish neither, which is not what you want. Leave the defaults unless you have a specific partner domain where encryption must be guaranteed, and handle that with a rule for that domain.

Doing this with a RE:NODE mail server#

The Mail Server line runs Stalwart, and the DNS records here - TXT for MTA-STS and TLS-RPT, TLSA for DANE - are yours to add at whoever hosts your DNS, the same as the MX, SPF, DKIM and DMARC records. Support forwards port 25 to the server so it can receive mail from the internet, and that port is what senders test when they apply your policy, so make sure the certificate presented there covers the name your MX points at before publishing anything.

The MTA-STS policy file needs a web host with a valid certificate on mta-sts.example.com. Any static host will do. On a web hosting plan, point an A record for mta-sts.example.com at the address shown for the proxy slot and the certificate is issued and renewed automatically; the policy is one text file in .well-known. Check that nothing in the site's configuration redirects that path.

An order of work that does not lose mail#

These records sit on top of the ones every mail domain needs, so check the foundation first. SPF, DKIM and DMARC decide whether your mail is believed; MX records decide where mail goes. TLS policy only describes how it gets there, and a policy written against a wrong MX is worse than none.

  1. Fix the certificate on port 25. It must be valid, in date, and cover every name your MX records point at. Until this is true, every later step reports failures.
  2. Publish TLS-RPT. Collect a week of reports with no policy at all, to see how senders currently reach you.
  3. Publish MTA-STS in testing mode with a one-day max_age. Read two to three weeks of reports.
  4. Switch to enforce, raise max_age, change the id. Keep reading reports; a renewal that fails in three months will show up there first.
  5. Add DANE only if your DNS is DNSSEC-signed and you have a written plan for key rollover.

The habit is the same one that makes a DMARC rollout safe - publish in reporting mode, read what comes back, then enforce - and DMARC reports and policy rollout describes it in more detail. Aggregate reports are the only feedback you get from other people's mail servers, and they are worth the dedicated mailbox they need.

Testing your setup#

From any machine with dig, curl and openssl:

bash
$ dig +short TXT _mta-sts.example.com$ curl -sv https://mta-sts.example.com/.well-known/mta-sts.txt$ dig +short TXT _smtp._tls.example.com$ dig +short MX example.com$ openssl s_client -connect mail.example.com:25 -starttls smtp \    -servername mail.example.com </dev/null | openssl x509 -noout -subject -dates$ dig +dnssec +short TLSA _25._tcp.mail.example.com

Check that the policy fetch returns 200 with no redirect, that the mx lines match the MX answer, that the certificate on port 25 names the MX host and is in date, and - for DANE - that the TLSA answer matches the key hash and the response is validated. Your domain and its certificate covers certificate renewal, which is where most of these setups eventually break.

FAQ#

Is my mail encrypted without any of this?

Usually, yes. Most large providers offer and use STARTTLS, so most mail travels encrypted. What you lack without MTA-STS or DANE is any guarantee: an attacker able to interfere with the connection or with DNS can force plain text or impersonate your server, and the sender will not notice.

Does MTA-STS encrypt mail I send to other people?

No. Your policy tells other servers how to deliver to you. Whether your outbound mail is protected depends on the recipient's domain publishing a policy and your server honouring it. Stalwart applies other domains' MTA-STS and DANE records when it sends.

What happens if my policy is wrong in enforce mode?

Senders that honour it refuse to deliver and keep the mail queued, typically for several days, before bouncing it to the original sender. Nothing reaches you and nothing tells you, apart from TLS-RPT reports. That is why testing mode comes first and why a policy change needs a new id.

Do I need DNSSEC for MTA-STS?

No. MTA-STS was designed for domains without DNSSEC; its trust comes from the HTTPS certificate on the policy host. DANE is the one that requires DNSSEC.

How long should max_age be?

A day while testing, so mistakes expire quickly. Once in enforce mode and stable, a week to a month is common, and longer gives better protection against an attacker blocking the policy fetch. Remember that a long max_age also means a long wait when you change mail servers.


Comments

Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.

0/2000