Microsoft 365 SPF Record Template
The correct microsoft 365 spf record for Exchange Online, plus when to add ESP includes and how to avoid PermError on crowded TXT records.

You migrated to Microsoft 365 in a weekend. Monday morning, marketing asks why SPF still points at the old Google include. A 41-person professional services firm in Copenhagen left include:_spf.google.com in DNS for eleven months after moving mailboxes to Exchange Online. Outbound mail mostly worked. SPF evaluation returned pass for Google's range, not Microsoft's. DMARC alignment failed on some hybrid calendar invites. A client's gateway quarantined proposals until someone noticed the TXT record never changed. The microsoft 365 spf record is not complicated. One include covers standard Exchange Online outbound. Complexity shows up when you stack marketing tools, ticketing SaaS, and payroll systems on the same domain without counting DNS lookups.
Microsoft 365 SPF Record (Exchange Online Only)
If every message leaves through Microsoft 365 and no third-party tool sends as your domain, publish this TXT on the root domain:
v=spf1 include:spf.protection.outlook.com -allWhat it does
include:spf.protection.outlook.com delegates to Microsoft's SPF, which authorizes current Exchange Online sending IPs. -all hard-fails everything else.
Where to publish
DNS host for your domain (Cloudflare, GoDaddy, Route53, Azure DNS). One TXT record on @ or root. Not in M365 admin. DNS only.
For full syntax rules, see zerohook.org/blog/spf-record-syntax-complete-reference.
M365 Plus ESP or SaaS (Common Templates)
M365 + Mailchimp on the same root domain (count lookups before publish):
v=spf1 include:spf.protection.outlook.com include:servers.mcsv.net -allM365 + HubSpot marketing mail:
v=spf1 include:spf.protection.outlook.com include:spf.hubspotemail.net -allM365 + SendGrid transactional:
v=spf1 include:spf.protection.outlook.com include:sendgrid.net -allIn Cloudflare: DNS → Add record → Type TXT → Name @ → Paste the single line → TTL Auto → Save. Remove any second TXT that starts with v=spf1. Two SPF records = PermError.
Validate at zerohook.org/spf-checker. Confirm lookup count stays at or below 10. If permerror, remove dead includes or move marketing to mail.yourdomain.com with its own SPF.
Frequently Asked Questions
Do I need a separate SPF for each subdomain?
Only if that subdomain sends mail with its own envelope-from. If Mailchimp sends as [email protected], publish SPF on mail.yourdomain.com, not only on the root.
Can I use ~all instead of -all on M365?
During a same-day migration test, maybe overnight. Production sending domains should use -all in 2026. Softfail weakens the signal receivers and auditors expect.
Microsoft says my domain is healthy. Why does Gmail still fail DMARC?
M365 domain health checks do not replace DMARC alignment on ESP mail. Enable DKIM in M365 (Admin → Domains → DKIM) and authenticate marketing tools separately.
Key takeaways
Standard M365-only SPF: v=spf1 include:spf.protection.outlook.com -all
Add one include per live ESP; remove old provider includes after migration.
One SPF TXT per domain; validate lookup count after every edit.
Pair SPF with DKIM and DMARC for Gmail and Microsoft receiver requirements.
Paste your TXT line at zerohook.org/spf-checker before you remove Google's include and wonder why nothing sends.
Share this analysis
Help others discover this content
About the author

The ZeroHook Team documents SPF and DKIM misconfigurations that still pass basic lookups but fail at Gmail and Microsoft 365.


