How mail between servers is secured, from DNSSEC to DANE, and why every one of the settings has to be right. Built on Postfix, on Microsoft 365 and on Stalwart.
Email between two servers was designed to be delivered, not to be private.
By default it is sent in the clear, or encrypted only if nobody interferes.
The settings that fix this all live in DNS. Each one closes a different gap. Get one wrong and mail is still delivered, so nothing tells you.
These posts cover:
What each setting protects: SPF, DKIM, DMARC, MTA-STS, TLS reporting and DANE.
Why DANE needs DNSSEC underneath it, and what goes wrong when a certificate is renewed.
How to set all of it up on Postfix, and prove it works.
What Microsoft 365 does and does not let you control.
How Stalwart handles the same settings, built in rather than added on.
Every check in these posts can be run against any domain, yours or anybody else’s.
Why Every Mail Setting Has To Be Right
Every layer of email security is designed to fall back to working rather than fail safely. Strip the STARTTLS line out of a greeting and an opportunistic sender carries on in the clear, which RFC 3207 both describes as an attack and, on a public server, forbids you to defend against. This post captures that man-in-the-middle in a lab, then walks the seven settings that protect a message in transit, showing for each one what it protects, what it does not, and how it fails open when it is wrong. From there to DANE: why a TLSA record is worthless without DNSSEC under it, why 3 1 1 and key reuse matter, and how a stale record is the one failure that closes rather than opens. Then a read-only census of UK banks, the big mail providers and the certificate authorities, counting how many actually do any of it.
Postfix, DANE And Every Setting Done Properly
Out of the box Postfix sends in the clear when the far end offers no TLS and takes mail from anybody claiming to be anybody. This is the other build: Postfix 3.10.13 with Dovecot for logins, Rspamd for SPF, DKIM and DMARC, and postfix-tlspol for DANE and MTA-STS. No plaintext in or out, port 25 never relays, a login owns its addresses in the envelope and the From header, sender domains that do not exist are refused, and a tampered or spoofed message never gets past DATA. Every reply was captured in a lab over IPv4 and IPv6, along with the five settings that silently do nothing until something else is set too, the certbot default that breaks DANE on renewal, and what all of it costs you in forwarded mail.
Microsoft 365: The Fisher-Price IT Edition
Most organisations do not run their own mail server. They pay Microsoft, and Exchange Online does the work. So this post holds Microsoft 365 to exactly the house rules the Postfix and Stalwart builds met, using nothing but Microsoft’s own documentation and read-only DNS against real tenants. Some of the rules it meets well: outbound DANE and MTA-STS are on by default, and inbound DANE with DNSSEC finally went GA. Several it cannot meet at all. There is no documented way to require inbound TLS from every sender, no way to reject an SPF hard fail at the door, nothing that rejects on a failed DKIM signature alone, and no control that drops mail from a sender domain that does not exist. DNSSEC is explicitly not planned for the mail host every tenant actually uses. The IPv6 rollout that was meant to take six months has left the NCSC’s own mailbox unreachable over IPv6 two years on. And the documentation contradicts itself on wildcards, on SPF, and on DNSSEC. This is the platform most of the country’s mail runs on, and this is what it will and will not let you do.
Stalwart: DANE And The Rest, Built In
Stalwart is a whole mail server in one binary: SMTP and IMAP and JMAP, SPF, DKIM, DMARC, ARC, DANE, MTA-STS, TLS reporting, a spam filter and the mail store, with no milter to wire up and no policy daemon to run beside it. This post holds it to the same house rules as the Postfix build and captures every reply in the lab. The rules all go on, but the story is in the detail: the settings live in a database rather than a file, the defaults as shipped accept plaintext and a tampered invoice, each rule lands in a different one of four configuration mechanisms, DKIM-fail rejection needs a Sieve script because the built-in check reports a tampered body as neutral, the unknown-sender check runs only after the whole message is in and fails open on a DNS error, and the MTA-STS sender bounces on the first attempt where the standard says it should defer. Built in is genuinely less to wire together. It is not the same as safe by default.