On May 5, 2025, Microsoft started rejecting emails that failed authentication checks. Hotmail, Outlook.com, and Live.com -- roughly 500 million active users -- stopped receiving unauthenticated messages from high-volume senders. The exact error: 550; 5.7.515 Access denied, sending domain does not meet the required authentication level.
Google and Yahoo had already moved in February 2024. If your SaaS app sends password resets, invoices, or notifications, all three major inbox providers now enforce authentication. Get it wrong and your emails land in spam or get dropped entirely.
The Stack at a Glance
Five protocols, each building on the last:
| Protocol | What It Does | Required By |
|---|---|---|
| SPF | Lists which servers can send for your domain | Google, Yahoo, Microsoft |
| DKIM | Cryptographically signs each message | Google, Yahoo, Microsoft |
| DMARC | Ties SPF and DKIM together, sets failure policy | Google, Yahoo, Microsoft |
| BIMI | Shows your brand logo in supporting inboxes | Optional |
| MTA-STS | Forces TLS encryption on inbound delivery | Optional |
SPF and DKIM are the foundation. DMARC is the policy layer. BIMI and MTA-STS come after the foundation is solid.
SPF
SPF is a DNS TXT record that lists which mail servers are allowed to send email for your domain. When Gmail receives a message from noreply@yourapp.com, it checks your SPF record against the sending server's IP. No match, no delivery.
dnsyourapp.com. IN TXT "v=spf1 include:_spf.resend.com include:sendgrid.net -all"
Use -all (hard fail) in production, not ~all (soft fail). Soft fail lets unauthorized senders through. Hard fail doesn't.
One critical limit: SPF allows a maximum of 10 DNS lookups per evaluation. Each include: counts as one. If you use four or five sending services, you can hit this silently. When you exceed 10, SPF returns a PermError and your legitimate emails start failing. The fix is to flatten your record -- replace nested include: statements with direct IP ranges, or cut down on the number of services you send from.
Use the SPF Record Generator to build the record, then check it with the SPF Record Checker to confirm you're under the lookup limit.
DKIM
DKIM adds a cryptographic signature to every outgoing email. Your ESP holds a private key and signs each message. You publish the matching public key in DNS. The receiving server fetches your public key, verifies the signature, and marks it dkim=pass or dkim=fail.
SPF verifies the sending server. DKIM verifies the message content itself. You need both.
Your ESP's domain authentication page will give you the exact DNS record to add -- usually a CNAME or TXT at a selector subdomain:
dnsresend._domainkey.yourapp.com. IN CNAME resend._domainkey.resend.com.
After adding it, send a test email to Gmail and check the raw headers (Show Original). You want to see this:
Authentication-Results: dkim=pass header.i=@yourapp.com header.s=resend
If you see dkim=fail, the public key in DNS doesn't match what your ESP is signing with. Re-copy the DNS record from your ESP's dashboard and re-add it.
If you run self-hosted mail rather than an ESP, use a 2048-bit RSA key minimum -- 1024-bit is rejected by all major providers in 2026.
DMARC
DMARC sits on top of SPF and DKIM. It tells receiving servers what to do when either check fails -- nothing, quarantine to spam, or reject outright -- and sends you daily reports about what's passing and failing.
It also enforces alignment: the From: header domain must match the domain that passed SPF or DKIM. This closes the spoofing loophole where a legitimate server could send from a fake address that technically passes SPF.
Rollout Strategy
Never start at p=reject. Start at p=none, read reports for four weeks, then tighten.
Month 1 - Monitor
dns_dmarc.yourapp.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourapp.com"
p=none blocks nothing but sends you daily XML aggregate reports. Use a free parser like Postmark's DMARC Digests to read them without decoding XML by hand. Your goal is to find every service sending email from your domain and make sure it appears in your SPF record.
Month 2 - Quarantine
dns"v=DMARC1; p=quarantine; pct=10; rua=mailto:dmarc@yourapp.com"
Start at pct=10 -- 10% of failing messages go to spam. Watch the reports, fix any remaining gaps, then gradually raise pct to 100.
Month 3+ - Reject
dns"v=DMARC1; p=reject; rua=mailto:dmarc@yourapp.com"
Full enforcement. Failing messages are dropped. Domain spoofing becomes essentially impossible.
Use the DMARC Record Generator to build the record with correct syntax.
BIMI
BIMI lets your brand logo appear next to your email in Gmail, Yahoo Mail, Apple Mail, and Fastmail. It requires DMARC at p=quarantine or p=reject with pct=100, plus a certificate from a CA:
- VMC (Verified Mark Certificate): Requires a registered trademark. $780 to $1,668/year. Shows logo plus a blue verified checkmark in Gmail.
- CMC (Common Mark Certificate): No trademark required -- Google started accepting these in 2026. Around $650/year. Shows logo, no checkmark.
The logo must be an SVG file meeting the Tiny PS spec. Your DNS record looks like:
dnsdefault._bimi.yourapp.com. IN TXT "v=BIMI1; l=https://yourapp.com/logo.svg; a=https://yourapp.com/vmc.pem"
For B2C products with brand recognition, BIMI is worth the investment. For a B2B SaaS with technical users, get DMARC to p=reject first -- the certificate cost adds up for marginal gain.
MTA-STS
MTA-STS tells sending mail servers they must use TLS when delivering to your domain -- the email equivalent of HSTS. Without it, a man-in-the-middle attacker could strip TLS and intercept email in plaintext.
Setup requires two things: a policy file hosted at https://mta-sts.yourapp.com/.well-known/mta-sts.txt, and a DNS TXT record pointing to it.
Policy file:
version: STSv1
mode: testing
mx: mail.yourapp.com
max_age: 86400
Start with mode: testing. Once TLS reports confirm no failures, switch to mode: enforce.
DNS record:
dns_mta-sts.yourapp.com. IN TXT "v=STSv1; id=20260601T000000"
Change the id= timestamp whenever you update the policy file -- this tells sending servers to re-fetch rather than serve a stale cache.
Pair it with TLS-RPT to receive reports when senders hit TLS failures:
dns_smtp._tls.yourapp.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@yourapp.com"
Testing Your Setup
Send a test email to a Gmail address and open it with Show Original. The Authentication-Results header should show all three passing:
spf=pass ... dkim=pass ... dmarc=pass
If any show fail, that protocol is misconfigured. The Email Header Analyzer parses these headers and highlights pass/fail results, delays, and routing hops in a readable format.
For DNS propagation, use dig to verify records are live:
Bashdig txt yourapp.com +short # SPF dig txt _dmarc.yourapp.com +short # DMARC dig txt resend._domainkey.yourapp.com +short # DKIM
Common Fixes
SPF PermError -- you've exceeded 10 DNS lookups. Flatten the record to direct IPs or remove sending services you no longer use.
DKIM key mismatch -- your ESP re-generated its keys and you haven't updated DNS. Re-copy the record from your ESP's dashboard.
DMARC alignment fail despite SPF pass -- your ESP is sending from bounces.yourapp.com but your From: says yourapp.com. Switch to relaxed alignment (aspf=r) or align the sending subdomain.
BIMI logo not showing in Gmail -- Gmail requires a VMC or CMC certificate. Without one, logos only appear in Yahoo and Apple Mail.
MTA-STS 404 -- the policy file at https://mta-sts.yourapp.com/.well-known/mta-sts.txt isn't accessible. Confirm the subdomain has a DNS A record and the path returns HTTP 200.
DNS Records Cheat Sheet
dns# SPF yourapp.com. IN TXT "v=spf1 include:_spf.resend.com -all" # DKIM resend._domainkey.yourapp.com. IN CNAME resend._domainkey.resend.com. # DMARC (start here, move to quarantine then reject) _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"
Where to Start
- SPF -- one record, 15 minutes, immediately addresses the Microsoft requirement.
- DKIM -- follow your ESP's setup guide, usually 2-3 DNS records.
- DMARC at
p=none-- takes 5 minutes, starts sending you reports. - Read reports for 4 weeks -- find every sending source and close SPF gaps.
- Quarantine then reject -- tighten policy gradually over 6 to 8 weeks.
- MTA-STS -- add once the core stack is stable.
- BIMI -- only after
p=rejectis in place.
Related DevToolLab Tools
- SPF Record Generator - Build a valid SPF record from your list of sending services
- DMARC Record Generator - Generate a DMARC record with correct syntax and all parameters
- DKIM Record Checker - Verify your public key is correctly published in DNS
- Email Header Analyzer - Parse raw email headers to see SPF, DKIM, and DMARC pass/fail at a glance
Conclusion
Email authentication is non-negotiable in 2026. Google, Yahoo, and Microsoft all enforce it, and the window for getting away without it is closed. SPF, DKIM, and DMARC together take a few hours of work spread across 6 to 8 weeks -- most of that time is just waiting for DMARC reports to reveal what you missed. The DNS records themselves are each a one-liner.
Start with SPF and DKIM today. Add DMARC at p=none and let it run for a month. Then tighten to p=quarantine and eventually p=reject. MTA-STS and BIMI are worth adding once the core stack is locked in. The DevToolLab email tools cover every step from generating records to verifying they propagated correctly.
