Since May 5, 2025, Microsoft has been refusing mail that cannot prove where it came from. Outlook.com, Hotmail and Live.com, somewhere around half a billion active mailboxes, now bounce unauthenticated messages from high-volume senders with this:
550; 5.7.515 Access denied, sending domain does not meet the required authentication level
Google and Yahoo got there first, back in February 2024. That means all three of the inbox providers that matter now check your DNS before they accept your password resets and receipts. I put the full version of this, with every record and a longer troubleshooting section, on DevToolLab. Here is the short version.
Five Records, Two of Them Non-Negotiable
| Record | Job | Status |
|---|---|---|
| SPF | Declares which servers may send as you | Enforced by all three |
| DKIM | Signs each message so tampering shows | Enforced by all three |
| DMARC | Binds the two above to your visible From address and sets the penalty | Enforced by all three |
| BIMI | Puts your logo in the inbox | Nice to have |
| MTA-STS | Demands TLS on inbound delivery | Nice to have |
Build the first three. Treat the last two as things you add once the first three are boring.
SPF: One Line, One Trap
SPF is a TXT record naming the servers permitted to send for your domain. A receiver compares the connecting IP against that list.
yourapp.com. IN TXT "v=spf1 include:_spf.resend.com include:sendgrid.net -all"
End it with -all, not ~all. The tilde is a soft fail, which politely suggests a receiver might want to consider being suspicious. The hyphen is a hard fail and actually means no.
Now the trap, because it bites quietly. SPF evaluation is capped at 10 DNS lookups, and each include: spends one. Add a marketing platform, a help desk, an invoicing tool and a transactional provider and you can cross that line without noticing. Past 10 you get a PermError, and a PermError means your genuine mail starts failing authentication with nothing obviously broken. Either flatten the record into literal IP ranges or drop services you no longer send from. Our SPF Record Checker counts the lookups for you, which is faster than reasoning about nested includes by hand.
DKIM: Signing the Message, Not the Server
SPF vouches for the machine. DKIM vouches for the content. Your provider signs outbound mail with a private key; you publish the public half at a selector subdomain, usually as a CNAME they hand you:
resend._domainkey.yourapp.com. IN CNAME resend._domainkey.resend.com.
Verify by mailing yourself at Gmail and opening Show Original:
Authentication-Results: dkim=pass header.i=@yourapp.com header.s=resend
A dkim=fail almost always means the key in DNS and the key doing the signing have drifted apart, which is a re-copy from your provider's dashboard rather than a debugging session. Running your own mail server instead? Use 2048-bit RSA. Every major receiver refuses 1024-bit in 2026.
DMARC: The Policy Layer
DMARC does two jobs. It decides what happens when SPF or DKIM fails, and it insists that whichever check passed belongs to the same domain the recipient can actually see in the From line. That second part is what kills spoofing, because a message can pass SPF on an attacker's own domain while displaying yours.
Resist going straight to enforcement. A p=reject rolled out blind will silently delete real mail from a service you forgot you owned.
Month one, watch and learn:
_dmarc.yourapp.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourapp.com"
Nothing is blocked. You just start receiving daily XML aggregate reports, which a free parser such as Postmark's DMARC Digests will turn into something a human can read. The job this month is inventory: find every system sending as you and make sure SPF knows about it.
Month two, start applying pressure to a slice of the traffic:
"v=DMARC1; p=quarantine; pct=10; rua=mailto:dmarc@yourapp.com"
Ten percent of failures go to spam. Read the reports, close the gaps, raise pct toward 100.
Month three, commit:
"v=DMARC1; p=reject; rua=mailto:dmarc@yourapp.com"
Failures are discarded and impersonating your domain stops being practical.
BIMI: Paying for a Logo
BIMI puts your brand mark beside your messages in Gmail, Yahoo, Apple Mail and Fastmail. The entry fee is DMARC already at quarantine or reject with pct=100, plus a certificate:
A Verified Mark Certificate runs $780 to $1,668 a year and requires a registered trademark, and it is the only route to the blue checkmark in Gmail. A Common Mark Certificate costs around $650 a year, skips the trademark requirement, and Google began honoring them in 2026, though without the checkmark. Your logo has to be SVG conforming to the Tiny PS profile.
default._bimi.yourapp.com. IN TXT "v=BIMI1; l=https://yourapp.com/logo.svg; a=https://yourapp.com/vmc.pem"
Consumer brand with recognition worth reinforcing? Probably worth it. B2B tool whose users read mail in a client that ignores BIMI anyway? Spend the money on getting to p=reject instead.
MTA-STS: HSTS for Mail
MTA-STS instructs sending servers that TLS is mandatory when delivering to you, closing the downgrade attack where someone strips encryption in transit and reads plaintext. It needs a hosted policy file plus a DNS pointer.
The file lives at https://mta-sts.yourapp.com/.well-known/mta-sts.txt:
version: STSv1
mode: testing
mx: mail.yourapp.com
max_age: 86400
Begin in testing. Move to enforce after reports show nothing legitimate is being refused.
_mta-sts.yourapp.com. IN TXT "v=STSv1; id=20260601T000000"
Bump that id every time you edit the policy file, otherwise senders keep serving themselves a cached copy. Add TLS-RPT alongside it so failures reach you:
_smtp._tls.yourapp.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@yourapp.com"
Confirming It Actually Works
Mail a Gmail address, open Show Original, and look for three passes on one line:
spf=pass ... dkim=pass ... dmarc=pass
Anything reading fail points at exactly which record to revisit. Our Email Header Analyzer pulls those headers apart and surfaces the pass and fail states along with routing hops and delays, which beats squinting at raw text.
Then confirm the records are actually live rather than just saved in a control panel:
dig txt yourapp.com +short # SPF
dig txt _dmarc.yourapp.com +short # DMARC
dig txt resend._domainkey.yourapp.com +short # DKIM
Five Failures You Will Probably Hit
An SPF PermError means you crossed 10 lookups. Flatten or prune.
A DKIM mismatch means your provider rotated keys and DNS did not follow.
DMARC failing while SPF passes is an alignment problem: the provider is bouncing from something like bounces.yourapp.com while your From says yourapp.com. Relax alignment with aspf=r or line the subdomains up.
No BIMI logo in Gmail means no VMC or CMC. Yahoo and Apple Mail are more forgiving; Gmail is not.
An MTA-STS 404 means the policy URL is not reachable. Check the subdomain resolves and the path returns 200.
Everything In One Block
# SPF
yourapp.com. IN TXT "v=spf1 include:_spf.resend.com -all"
# DKIM
resend._domainkey.yourapp.com. IN CNAME resend._domainkey.resend.com.
# DMARC (begin here, escalate later)
_dmarc.yourapp.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourapp.com; adkim=r; aspf=r"
# BIMI (optional)
default._bimi.yourapp.com. IN TXT "v=BIMI1; l=https://yourapp.com/logo.svg; a=https://yourapp.com/vmc.pem"
# MTA-STS
_mta-sts.yourapp.com. IN TXT "v=STSv1; id=20260601T000000"
# TLS-RPT
_smtp._tls.yourapp.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@yourapp.com"
The Order To Do This In
Publish SPF first, since it is a single record and it directly answers the Microsoft requirement. Add DKIM next by following your provider's guide, typically two or three records. Then put DMARC up at p=none and leave it alone for four weeks while the reports tell you which forgotten system is sending as you. Tighten to quarantine, walk pct up to 100, then reject, spread over roughly six to eight weeks. MTA-STS goes on once that is stable. BIMI goes last, after reject.
Total hands-on work is a few hours. The calendar time is almost entirely waiting for DMARC reports to tell you what you did not know you were running. The longer guide covers the troubleshooting cases in more depth if something refuses to pass.
Top comments (0)