SPF for Microsoft 365 / Exchange Online
Add include:spf.protection.outlook.com to your domain's single SPF TXT record, never publish two SPF records. If you send only through Microsoft 365 / Exchange Online, the whole record is:
v=spf1 include:spf.protection.outlook.com -all
One SPF TXT record per domain/subdomain. Commercial + GCC use include:spf.protection.outlook.com. Sovereign clouds differ: GCC High / DoD use include:spf.protection.office365.us; Microsoft 365 operated by 21Vianet uses include:spf.protection.partner.outlook.cn. Microsoft recommends ending in -all (hard fail) rather than ~all, because DMARC effectively ignores an SPF ~all soft-fail when the message has no DKIM signature. The spf.protection.outlook.com include resolves to ~2 DNS lookups; adding several other vendors risks blowing the 10-lookup limit (permerror). Do NOT flatten the Microsoft include to ip4: values -- Microsoft's sending IPs are dynamic and change often. On-prem hybrid senders should be added as ip4: (which cost zero lookups), not extra includes. Each subdomain that sends mail needs its own SPF record; route uncontrolled bulk senders through a subdomain so their SPF failures don't harm your primary domain. The onmicrosoft.com initial domain already has a Microsoft-managed SPF record you can't edit.
DKIM for Microsoft 365 / Exchange Online
M365 publishes DKIM public keys behind two CNAMEs that point into Microsoft's infrastructure -- you never publish a TXT public key yourself. Publish BOTH CNAMEs (Microsoft rotates keys by alternating selector1/selector2). Get the exact per-domain target values from the source of truth, never hand-type them: Defender portal -> https://security.microsoft.com/authentication -> DKIM tab -> select the domain -> the 'Publish CNAMEs' flyout shows both records; or Exchange Online PowerShell: Get-DkimSigningConfig -Identity contoso.com | Format-List Selector1CNAME,Selector2CNAME. After the CNAMEs resolve in DNS, you MUST enable signing -- flip the DKIM toggle to Enabled in the Defender portal, or run Set-DkimSigningConfig -Identity contoso.com -Enabled $true. Publishing the CNAMEs alone does not sign mail. IMPORTANT (May 2025 format change): brand-new custom domains use a new target format that includes your onmicrosoft prefix plus a dynamically-assigned partition character and -v1.dkim.mail.microsoft; existing/older domains still use the classic *.onmicrosoft.com target. The two formats can't coexist for a selector, which is exactly why you must copy the exact values from the portal/PowerShell rather than guess.
Method: CNAME · Selector(s): selector1, selector2
New (2025+) format: Host: selector1._domainkey Value: selector1-contoso-com._domainkey.contoso.r-v1.dkim.mail.microsoft Host: selector2._domainkey Value: selector2-contoso-com._domainkey.contoso.r-v1.dkim.mail.microsoft Classic format (existing domains): Host: selector1._domainkey Value: selector1-contoso-com._domainkey.contoso.onmicrosoft.com Host: selector2._domainkey Value: selector2-contoso-com._domainkey.contoso.onmicrosoft.com (contoso-com = your domain with dots->dashes; contoso = your onmicrosoft prefix; the partition char e.g. r/n is assigned by Microsoft -- use the exact value the portal gives you.)
DMARC for Microsoft 365 / Exchange Online
Publish a single TXT record at _dmarc.<yourdomain> (e.g. _dmarc.contoso.com). DMARC passes when SPF or DKIM passes AND is aligned with the From: domain. For M365, SPF alignment depends on the 5321.MailFrom, and DKIM alignment depends on the signing d= domain matching your From domain -- which is why you must enable custom-domain DKIM signing (not rely on the default *.onmicrosoft.com signature, which is NOT aligned to your custom From domain and won't satisfy DMARC alignment on its own). Start at p=none with a rua reporting address to observe, then move to p=quarantine and finally p=reject. Subdomains inherit the parent DMARC policy unless you set sp= or publish a _dmarc record on the subdomain; undefined subdomains are covered by the parent record, so a parent record protects sub-domains you haven't explicitly defined. Microsoft recommends configuring DMARC (even in p=none 'take no action' mode) early alongside a reporting service to discover all your legitimate senders before tightening.
v=DMARC1; p=reject; pct=100; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1; adkim=s; aspf=s
Common Microsoft 365 / Exchange Online mistakes
- Publishing the DKIM CNAMEs but forgetting to flip DKIM signing to Enabled (Defender portal DKIM toggle / Set-DkimSigningConfig -Enabled $true) -- keys in DNS do nothing until signing is turned on.
- Hand-typing the DKIM CNAME target instead of copying it from the portal/PowerShell. Since the May 2025 format change, new domains use ...<prefix>.<char>-v1.dkim.mail.microsoft while older domains use ...<prefix>.onmicrosoft.com -- guessing the wrong one leaves DKIM in CnameMissing and signing never enables.
- Creating the DKIM records as TXT records instead of CNAME. M365 uses CNAMEs that delegate to Microsoft-hosted keys; a TXT here is wrong.
- SPF 10-lookup blowup: stacking spf.protection.outlook.com with several other vendor includes (marketing, ticketing, CRM) pushes past 10 DNS lookups and returns permerror = SPF fail for ALL mail. Move third-party senders to subdomains or replace stable vendors with ip4:.
- Flattening the Microsoft include to hard-coded IPs -- Microsoft's outbound IP set is dynamic; flattened IPs go stale and legit mail starts failing SPF.
- Assuming the automatic *.onmicrosoft.com DKIM signature satisfies DMARC. It signs with d=<tenant>.onmicrosoft.com, which is NOT aligned to your custom From domain, so DMARC (which needs alignment) still fails until you enable custom-domain DKIM.
- Duplicate/trailing-dot SPF mistakes: two SPF records on one domain = permerror; a trailing period (outlook.com.) or 'include=' instead of 'include:' silently breaks the record.
- Forgetting a per-subdomain SPF/DKIM config -- a record on contoso.com does NOT cover marketing.contoso.com; each sending subdomain needs its own SPF record and DKIM configuration.
Frequently asked questions
What SPF record do I need for Microsoft 365 / Exchange Online?
Add include:spf.protection.outlook.com to your domain's single SPF TXT record. A domain that sends only through Microsoft 365 / Exchange Online would use: v=spf1 include:spf.protection.outlook.com -all. One SPF TXT record per domain/subdomain. Commercial + GCC use include:spf.protection.outlook.com. Sovereign clouds differ: GCC High / DoD use include:spf.protection.office365.us; Microsoft 365 operated by 21Vianet uses include:spf.protection.partner.outlook.cn. Microsoft recommends ending in -all (hard fail) rather than ~all, because DMARC effectively ignores an SPF ~all soft-fail when the message has no DKIM signature. The spf.protection.outlook.com include resolves to ~2 DNS lookups; adding several other vendors risks blowing the 10-lookup limit (permerror). Do NOT flatten the Microsoft include to ip4: values -- Microsoft's sending IPs are dynamic and change often. On-prem hybrid senders should be added as ip4: (which cost zero lookups), not extra includes. Each subdomain that sends mail needs its own SPF record; route uncontrolled bulk senders through a subdomain so their SPF failures don't harm your primary domain. The onmicrosoft.com initial domain already has a Microsoft-managed SPF record you can't edit.
How do I set up DKIM for Microsoft 365 / Exchange Online?
M365 publishes DKIM public keys behind two CNAMEs that point into Microsoft's infrastructure -- you never publish a TXT public key yourself. Publish BOTH CNAMEs (Microsoft rotates keys by alternating selector1/selector2). Get the exact per-domain target values from the source of truth, never hand-type them: Defender portal -> https://security.microsoft.com/authentication -> DKIM tab -> select the domain -> the 'Publish CNAMEs' flyout shows both records; or Exchange Online PowerShell: Get-DkimSigningConfig -Identity contoso.com | Format-List Selector1CNAME,Selector2CNAME. After the CNAMEs resolve in DNS, you MUST enable signing -- flip the DKIM toggle to Enabled in the Defender portal, or run Set-DkimSigningConfig -Identity contoso.com -Enabled $true. Publishing the CNAMEs alone does not sign mail. IMPORTANT (May 2025 format change): brand-new custom domains use a new target format that includes your onmicrosoft prefix plus a dynamically-assigned partition character and -v1.dkim.mail.microsoft; existing/older domains still use the classic *.onmicrosoft.com target. The two formats can't coexist for a selector, which is exactly why you must copy the exact values from the portal/PowerShell rather than guess.
Do I need DMARC when sending through Microsoft 365 / Exchange Online?
Publish a single TXT record at _dmarc.<yourdomain> (e.g. _dmarc.contoso.com). DMARC passes when SPF or DKIM passes AND is aligned with the From: domain. For M365, SPF alignment depends on the 5321.MailFrom, and DKIM alignment depends on the signing d= domain matching your From domain -- which is why you must enable custom-domain DKIM signing (not rely on the default *.onmicrosoft.com signature, which is NOT aligned to your custom From domain and won't satisfy DMARC alignment on its own). Start at p=none with a rua reporting address to observe, then move to p=quarantine and finally p=reject. Subdomains inherit the parent DMARC policy unless you set sp= or publish a _dmarc record on the subdomain; undefined subdomains are covered by the parent record, so a parent record protects sub-domains you haven't explicitly defined. Microsoft recommends configuring DMARC (even in p=none 'take no action' mode) early alongside a reporting service to discover all your legitimate senders before tightening.