Skip to main content

SPF, DKIM, DMARC, ARC and spoof intelligence

Microsoft documentedDefender for Office 365 · Source checked 2026-10-22 · Not yet verified in tenant · Sources: [1][2][3][4][5][6][7][8][9][10][11][12]

What it is​

SPF lists the servers allowed to send for the envelope domain. DKIM signs the message with a key the domain owner controls. DMARC ties both to the From domain the user sees, publishes what to do on failure, and asks for reports. ARC lets a trusted intermediary vouch for the results it saw before it modified the message.

In Microsoft 365 these checks run in both directions. Outbound, Exchange Online signs with DKIM once you enable it per domain. Inbound, Exchange Online Protection runs SPF, DKIM and DMARC on every message, folds the results into one verdict called composite authentication, and hands that to spoof intelligence and the anti-phishing policy. Policy actions, presets and impersonation settings are in anti-phishing and presets; the service map is in the overview.

Spoofing is a forged From header and usually fails authentication. Impersonation is a lookalike user, domain or brand, and it can pass SPF, DKIM and DMARC because the attacker owns the lookalike domain. Authentication stops the first. Only Defender for Office 365 impersonation protection addresses the second.

Licensing and prerequisites​

  • Inbound checks, composite authentication, spoof intelligence, the TABL spoofed senders tab and Honor DMARC are Exchange Online Protection features in every cloud mailbox.
  • Impersonation protection and Threat Explorer need Defender for Office 365 Plan 1 or Plan 2.
  • Outbound DKIM needs the custom domain verified in Microsoft 365 and write access to its DNS zone.
  • Roles: Organization Management or Security Administrator in Exchange Online, or Global Administrator in Entra. Unified RBAC: Authorization and settings/Security settings/Core Security settings (manage). Learn notes the Entra Security Administrator role cannot open Email authentication settings in the portal.
  • Enhanced Filtering needs Organization Management or Exchange Administrator, and an inbound connector already carrying the gateway traffic.

How it works​

SPF​

One TXT record per sending domain or subdomain. Microsoft 365 needs include:spf.protection.outlook.com (commercial and GCC), spf.protection.office365.us (GCC High and DoD) or spf.protection.partner.outlook.cn (21Vianet). Use ip4: or ip6: only for on-premises servers such as hybrid Exchange. End with -all (recommended), ~all or ?all (testing only). Receivers check the MAIL FROM (5321.MailFrom, P1) domain, not the From header.

Evaluation stops at the first match and counts DNS lookups. include, a, mx, exists and redirect cost one each, nested includes add theirs, and more than 10 returns permerror with an NDR such as "The message required too many lookups". ip4, ip6 and all are free. Learn's fixes: IP literals for stable vendors, subdomains so each gets its own budget of 10, and never flatten spf.protection.outlook.com. Subdomains do not inherit SPF, one record per name, parked domains get v=spf1 -all, and onmicrosoft.com is read-only. DMARC treats ~all and -all both as failures, but Learn says the DMARC policy is effectively ignored for ~all when the message is also unsigned.

DKIM​

Exchange Online does not sign custom-domain mail until you enable it; until then it carries the onmicrosoft.com signature, which never aligns with your From domain. Each domain or subdomain gets two CNAMEs, selector1._domainkey and selector2._domainkey, pointing at Microsoft-hosted keys. One is active, the other takes over at rotation. Domains added since May 2025 use selector1-contoso-com._domainkey.contoso.<partition>-v1.dkim.mail.microsoft with a Microsoft-assigned partition character; older domains keep ...contoso.onmicrosoft.com. Copy the targets from Get-DkimSigningConfig, never type them.

Default key size is 1024-bit; 2048-bit is set at creation or rotation, one selector per rotation. Rotation takes 96 hours. onmicrosoft.com is signed automatically but never rotated automatically. Mail inside the tenant is not signed.

DMARC​

A TXT record at _dmarc.<domain>. p= is none, quarantine or reject; pct= samples it, default 100. rua= takes the daily aggregate XML report, ruf= the per-message failure report; Microsoft 365 sends aggregate reports only. aspf and adkim choose relaxed (organisational domain, default) or strict (exact FQDN) alignment. DMARC passes when SPF or DKIM both passes and aligns with the From domain. contoso.onmicrosoft.com never aligns with contoso.com, which is why DKIM is not optional.

A parent record covers every subdomain without its own, including nonexistent ones. The sp= tag is in RFC 7489 but not on the Learn page. Microsoft 365 sends aggregate reports only for domains whose MX points directly at it, and an external report domain must publish contoso.com._report._dmarc with value v=DMARC1;. Outbound cost: with p=quarantine or p=reject on your domain, your own mail that fails DMARC at the destination goes through the high-risk delivery pool with no override.

Composite authentication and spoof intelligence​

EOP writes the results into Authentication-Results and adds compauth=<pass | softpass | fail | none> reason=<code>. Composite authentication combines SPF, DKIM and DMARC with implicit signals (sender reputation, recipient history, behaviour) and judges the From domain. A compauth=fail does not block by itself. Spoof intelligence decides whether the failing sender looks legitimate (lists, SaaS, internal apps) or suspicious, and the anti-phishing policy applies the action. An explicit failure is a DMARC fail under p=quarantine or p=reject, reason 000. An implicit failure is no or weak records, reason 001. Reason codes are listed under Verify.

Honor DMARC in anti-phishing policy​

Honor DMARC record policy when the message is detected as spoof controls explicit failures. On: p=quarantine mail goes to Junk or quarantine, p=reject mail is quarantined or rejected at SMTP with 550 5.7.1, p=none gets no DMARC action. Off: explicit failures fall back to the spoof intelligence action. Turning spoof intelligence off removes implicit protection only. Behind a gateway, Honor DMARC only works with Enhanced Filtering on the connector. Enforced DMARC failures never appear in the spoof intelligence insight.

ARC and third-party gateways​

A gateway, forwarder or list in front of Microsoft 365 makes the connecting IP the gateway, so SPF fails; if it rewrites content, DKIM and DMARC fail too. ARC fixes the modification problem: the intermediary records what it saw in ARC-Authentication-Results, signs with ARC-Message-Signature and seals with ARC-Seal. Microsoft 365 honours the chain only if the ARC-Seal d= is a trusted sealer. Trust the vendor's signing domain (Proofpoint is pphosted.com), not your own. ARC does not bypass spam, bulk, mail flow rules or sender lists.

Enhanced Filtering for Connectors fixes the IP problem. EOP skips the gateway hop (last IP automatically, or a list) and evaluates the true source, which flips authentication from implicit to explicit. Learn also says it recovers from DKIM failures caused by non-ARC gateways. Both together are the normal pattern for a Proofpoint or Mimecast front end. Only linear routing is supported.

Configure​

Outbound DKIM for a custom domain:

  1. Defender portal > Email & collaboration > Policies & rules > Threat policies > Email authentication settings (https://security.microsoft.com/authentication), DKIM tab.
DKIM tab before setup. The custom domain has no keys and the toggle is off. Source: Microsoft Learn, CC BY 4.0.
DKIM tab before setup. The custom domain has no keys and the toggle is off. Source: Microsoft Learn, CC BY 4.0. · captured 2026-10-22
  1. Slide the toggle. A Client error dialog shows the CNAME values; select OK. Status becomes CnameMissing.
  2. Click the row, copy both Publish CNAMEs values, create them as CNAMEs with TTL 3600. Enter only the host part; Cloudflare must be DNS only; Route 53 needs a trailing dot.
  3. In the flyout, turn on Sign messages for this domain with DKIM signatures. Status changes to Signing once the CNAMEs are detected.
Flyout after signing is on, with Rotate DKIM keys at the bottom. Source: Microsoft Learn, CC BY 4.0.
Flyout after signing is on, with Rotate DKIM keys at the bottom. Source: Microsoft Learn, CC BY 4.0. · captured 2026-10-22
  1. Rotation: flyout > Rotate DKIM keys. Status reads Rotating keys for 96 hours.

Trusted ARC sealers:

  1. Same page, ARC tab > Add (or Edit).
  2. Enter the vendor signing domain from ARC-Seal d= in a test message. Save. Allow 30 minutes.
Without a trusted sealer, the gateway's rewrite fails SPF, DKIM and DMARC and the message lands in Junk, quarantine or is rejected. Source: Microsoft Learn, CC BY 4.0.
Without a trusted sealer, the gateway's rewrite fails SPF, DKIM and DMARC and the message lands in Junk, quarantine or is rejected. Source: Microsoft Learn, CC BY 4.0. · captured 2026-10-22
With the sealer trusted, ARC passes, spoof passes and the message reaches the Inbox. Source: Microsoft Learn, CC BY 4.0.
With the sealer trusted, ARC passes, spoof passes and the message reaches the Inbox. Source: Microsoft Learn, CC BY 4.0. · captured 2026-10-22

Honor DMARC and spoof actions:

  1. Threat policies > Anti-phishing > policy > Edit protection settings. Turn on Enable spoof intelligence and Honor DMARC record policy when the message is detected as spoof.
  2. Set the p=quarantine action (Quarantine or Junk), the p=reject action (Quarantine or Reject), the spoof intelligence action and the quarantine policy. See anti-phishing and presets for recommended values.
The Honor DMARC checkbox and the two per-policy action pickers it unlocks. Source: Microsoft Learn, CC BY 4.0.
The Honor DMARC checkbox and the two per-policy action pickers it unlocks. Source: Microsoft Learn, CC BY 4.0. · captured 2026-10-22

Spoof intelligence insight and overrides:

  1. Threat policies > Tenant Allow/Block Lists > Spoofed senders > View spoofing activity (https://security.microsoft.com/spoofintelligence). Seven days of spoofed user, sending infrastructure (PTR domain, <ip>/24 without PTR, or DKIM domain), count, spoof type and verdict.
  2. Select rows > Bulk actions > Allow to spoof or Block from spoofing. The entry moves to the Spoofed senders tab as a pair scoped to that domain plus that infrastructure.
  3. To pre-create a pair: Spoofed senders tab > Add, up to 20 pairs, Internal or External, Allow or Block. Wildcard on one side only.
The spoof intelligence insight card that opens the seven-day detections list. Source: Microsoft Learn, CC BY 4.0.
The spoof intelligence insight card that opens the seven-day detections list. Source: Microsoft Learn, CC BY 4.0. · captured 2026-10-22

Enhanced Filtering for Connectors:

  1. Threat policies > Rules > Enhanced filtering (https://security.microsoft.com/skiplisting) > the inbound connector.
  2. Automatically detect and skip the last IP address, or Skip these IP addresses with the gateway's public IPs or CIDRs. IPv6 is PowerShell only.
  3. Apply to a small set of users first, then the whole organisation. Disable SCL -1 mail flow rules for the connector.
Mail flow once skip listing is on: EOP evaluates the original internet sender instead of the gateway. Source: Microsoft Learn, CC BY 4.0.
Mail flow once skip listing is on: EOP evaluates the original internet sender instead of the gateway. Source: Microsoft Learn, CC BY 4.0. · captured 2026-10-22

SPF and DMARC have no portal or cmdlet; create them at the DNS host. Exception: the onmicrosoft.com DMARC record goes in the Microsoft 365 admin center, Settings > Domains > the domain > DNS records > Add record, TXT, name _dmarc, value v=DMARC1; p=reject.

Verify​

Inbound: open the last Authentication-Results header on a received message. Expect this shape:

Authentication-Results: spf=pass (sender IP is 203.0.113.10) smtp.mailfrom=contoso.com;
dkim=pass (signature was verified) header.d=contoso.com;
dmarc=pass action=none header.from=contoso.com;
compauth=pass reason=100
  • spf= pass, fail, softfail, neutral, none, temperror, permerror; smtp.mailfrom is the P1 domain.
  • dkim= pass, fail with reason, none; header.d is the signing domain.
  • dmarc= pass, fail, bestguesspass, none; action= none, quarantine, oreject, pct.quarantine, pct.reject, permerror, temperror.
  • compauth reason: 000 explicit fail, 001 implicit fail, 002 admin block, 010 DMARC fail on an accepted domain, 1xx pass, 130 ARC override, 2xx softpass, 3xx not checked, 4xx bypassed, 6xx intra-org fail, 7xx implicit pass.
  • X-Forefront-Antispam-Report: CAT:SPOOF with SFTY:9.11 (intra-org) or 9.22 (cross-domain) is spoof intelligence. CAT:DIMP, UIMP, BIMP, GIMP, SFTY:9.19 or 9.20 are impersonation. SFV:SKA, SKI, SKN mean an allow list or rule bypassed filtering.
  • ARC: arc=pass and oda=1 in ARC-Authentication-Results means chain verified, sealer trusted. cv= per ARC-Seal shows where a chain broke.
  • Enhanced Filtering stamps X-MS-Exchange-ExternalOriginalInternetSender on a recipient match and X-MS-Exchange-SkipListedInternetSender whenever enabled.
  • X-MS-Exchange-Organization-AuthAs: TODO. Learn's header reference does not document it; confirm against a known message in the dev tenant.

Outbound DKIM: send to an outlook.com or gmail.com mailbox (not AOL). DKIM-Signature must show d=contoso.com and the expected s= selector; the receiver's Authentication-Results should show dkim=pass header.d=contoso.com. Get-DkimSigningConfig should read Enabled True, Status Valid. The admin center DKIM diagnostic (Run Tests: DKIM) needs Global Administrator and is not in GCC, GCC High, DoD or 21Vianet.

DNS: Learn points to free online SPF lookup tools without naming one; Resolve-DnsName or dig give the raw answer. Reports: Spoof detections and Threat protection status show the effect over time; Threat Explorer (Plan 2) or Real-time detections (Plan 1) give per-message detail.

Troubleshoot​

SymptomLikely causeFix
spf=permerror, NDR says too many lookupsMore than 10 DNS lookups after expanding includesReplace stable vendor includes with ip4, move vendors to subdomains, never flatten the Microsoft include
spf=permerror with a short recordTwo TXT records starting v=spf1, an include that does not resolve, trailing period, include= or a space after the colonMerge to one record, query the include target, fix syntax
DKIM toggle will not enable, Status stays CnameMissingHost entered as the FQDN so the zone was appended twice, TXT instead of CNAME, Cloudflare proxy on, wrong target format, only selector1 createdCopy targets from Get-DkimSigningConfig, enter host as selector1._domainkey only, DNS-only in Cloudflare, create both CNAMEs
Outbound mail shows dkim=noneSigning not enabled for that exact domain or subdomain, or test sent inside the tenantEnable DKIM per sending subdomain, test to an external mailbox
dkim=pass but dmarc=failheader.d is a vendor domain or onmicrosoft.com, not the From domainEnable DKIM on the From domain, or have the SaaS sign with d= your domain or subdomain
DMARC fail on legitimate SaaS mailMAIL FROM is the vendor's bounce domain and DKIM is the vendor's domain, so nothing alignsCustom return path and DKIM at the vendor on a dedicated subdomain with its own SPF and DKIM; short term, a TABL spoof allow for that domain and infrastructure pair
dmarc=fail action=oreject but the message was deliveredHonor DMARC off, or a TABL, safe sender, allowed domain or mail flow rule overrideCheck the anti-phish policy and the overrides listed in SFV
dmarc=fail on forwarded mailForwarding changes the connecting IP and often the bodyTrusted ARC sealer for the forwarder, or scoped TABL allow
arc=fail or oda=0Sealer domain not on the trusted list, or your own domain was added instead of the vendor'sRead d= from ARC-Seal, set it with Set-ArcConfig, wait 30 minutes
arc=none, no ARC-Seal headerGateway is not sealingEnable ARC at the vendor, or fall back to Enhanced Filtering plus an IP allow or skip-filter rule
cv=fail in the chainA later hop modified the message after sealing, or the sealer's key did not resolveCheck cv= per i= instance, nslookup -type=TXT <selector>._domainkey.<sealer>
Inbound mail from a gateway all fails SPF or lands in JunkMX points at the gateway and skip listing is off, so EOP sees the gateway IPEnable Enhanced Filtering on the connector, disable SCL -1 rules, trust the ARC sealer
Enhanced Filtering seems to do nothing for some usersRecipient list incomplete, a proxy address missing, or one recipient on the message not listedList every address, hybrid MailUsers by TargetAddress, then move to whole org
No DMARC aggregate reports from MicrosoftMX does not point directly at Microsoft 365, or external report domain lacks the _report._dmarc recordAccept that gateway tenants get none from Microsoft; publish the authorisation record for cross-domain rua
Your own mail routed through the high-risk poolYour domain has p=quarantine or p=reject and the message failed DMARC at the destinationFix the source alignment; there is no override
Legitimate sender shows the via tag or question markFrom domain differs from DKIM d= or MAIL FROM, or both SPF and DKIM failedAlign DKIM or MAIL FROM with the From domain, or allow the pair in spoof intelligence

Gotchas and limits​

  • Subdomains inherit DMARC but not SPF or DKIM. marketing.contoso.com needs its own SPF record and CNAME pair. Impersonation trusted domains do not cover subdomains either.
  • Forwarding always breaks SPF. DKIM survives only if the forwarder leaves body and signed headers alone. Plan ARC or scoped allows for every forwarding path you cannot remove.
  • p=none forever gives reports and nothing else. Expect false positives and read the aggregate reports before each step up.
  • The 10-lookup limit is counted at the receiver, stopping at the first match, so a record can be over budget for one destination and fine for another.
  • onmicrosoft.com: Microsoft owns SPF and DKIM, the DMARC record is yours. Publish p=reject if nothing legitimate sends from it.
  • Ed25519 is unsupported. Moving to 2048-bit takes two 96-hour rotations that cannot overlap.
  • The CNAME target format changed in 2025 and the two formats cannot coexist on one selector. Do not rebuild records from a blog post.
  • Set-ArcConfig -ArcTrustedSealers replaces the whole list. Read, then append.
  • TABL spoof entries never expire, cap 1024. A spoof allow from the Submissions page only happens if spoof intelligence actually blocked the message.
  • Enhanced Filtering recipient scope applies only when every recipient is listed. Microsoft 365 IPs, RFC 1918 and loopback cannot be skip-listed.
  • Microsoft 365 sends no ruf reports, and no aggregate reports for domains whose MX is not Microsoft 365.
  • Safe Senders and anti-spam allowed lists skip spoof protection. Prefer the scoped TABL spoof pair.

Rollout plan to p=reject​

  1. Inventory every service that puts your domain in a From header. Decide which get a dedicated subdomain.
  2. SPF: one record per sending domain and subdomain, -all, under 10 lookups. Parked domains get v=spf1 -all.
  3. DKIM: enable per domain and subdomain, 2048-bit, verify externally. Each SaaS signs with d= your subdomain.
  4. p=none with rua, long enough to catch quarterly senders. Fix alignment, not just authentication.
  5. p=quarantine with pct=10, raise as reports stay clean.
  6. p=reject, same ramp, subdomains first, parent last. Drop subdomain records once they match the parent.
  7. v=DMARC1; p=reject on onmicrosoft.com and every parked domain.
  8. Inbound in parallel: Honor DMARC on with reject, Enhanced Filtering and trusted ARC sealers for any gateway.

Further reading​

Only three qualified in the October 2025 to October 2026 window.

My notes​

TODO: Sohail's notes after verification.

Changelog​

DateChangeSource
2026-10-22Drafted from Learn, with Learn images and diagrams[1]