Exchange OnlineHow-to

SPF, DKIM and DMARC for your Microsoft 365 custom domain: a practical setup guide

Publish one correct SPF record, turn on DKIM signing in the Defender portal, then move DMARC from p=none to p=reject without blocking your own legitimate mail.

If your custom domain only has the SPF record the Microsoft 365 setup wizard asked for, you're a third of the way there. Receiving systems increasingly expect SPF, DKIM and DMARC to pass and to line up with the From address people actually see. In this post I'll set up all three for a domain that sends from Exchange Online, show how to confirm the result in message headers, and cover the mistakes that break them most often.

How this guide is organised: How it works → Step-by-step → Verify with DNS and message headers → Tips & gotchasFlow diagram of the article's sections in reading order: 1. How it works. 2. Step-by-step (3 steps: Publish one correct SPF record; Turn on DKIM signing for the custom domain; Roll out DMARC in stages). 3. Verify with DNS and message headers. 4. Tips & gotchas. Toolbox: Settings › Domains, onmicrosoft.com, selector1._domainkey, _dmarc, DKIM-Signature.1How it works2Step-by-step3Verify with DNS andmessage headers4Tips & gotchas1Publish one correct SPFrecord2Turn on DKIM signing forthe custom domain3Roll out DMARC in stagesTOOLBOXSettings › Domainsonmicrosoft.comselector1._domainkey_dmarcDKIM-SignatureHow this guide is organised: How it works → Step-by-step → Verify with DNS and message headers → Tips & gotchasFlow diagram of the article's sections in reading order: 1. How it works. 2. Step-by-step (3 steps: Publish one correct SPF record; Turn on DKIM signing for the custom domain; Roll out DMARC in stages). 3. Verify with DNS and message headers. 4. Tips & gotchas. Toolbox: Settings › Domains, onmicrosoft.com, selector1._domainkey, _dmarc, DKIM-Signature.1How it works2Step-by-step1Publish one correct SPF record2Turn on DKIM signing for the custom domain3Roll out DMARC in stages3Verify with DNS and message headers4Tips & gotchasTOOLBOXSettings › Domainsonmicrosoft.comselector1._domainkey_dmarcDKIM-Signature
At a glance: how this guide is organised · 3 steps · 5 key settings and tools

How it works#

  • SPF is a TXT record listing the servers allowed to send for the envelope (MAIL FROM) domain. On its own it says nothing about the From address in the mail client.
  • DKIM adds a signature to each message. The signing domain appears as d= in the DKIM-Signature header, and in Microsoft 365 the public keys are published through two CNAME records that point to Microsoft-hosted keys.
  • DMARC is a TXT record at _dmarc.yourdomain. A message passes when SPF or DKIM passes and that domain aligns with the From domain. The record tells receivers what to do with failures and where to send reports.

Before you start, you need the domain added and verified in Microsoft 365, access to its DNS host, and a list of every service that sends as your domain: marketing platforms, CRM and ticketing tools, scanners and on-premises servers. Microsoft already handles SPF and DKIM for your onmicrosoft.com domain.

Step 1: Publish one correct SPF record#

For a domain that only sends through Exchange Online, create a single TXT record at the root of the domain:

Text
v=spf1 include:spf.protection.outlook.com -all

If an on-premises server also sends for the domain, add its public IP in front, for example v=spf1 ip4:203.0.113.10 include:spf.protection.outlook.com -all. Keep these rules in mind:

  • One SPF record per domain or subdomain. Two records produce a permanent error (permerror), so merge them.
  • Ten DNS lookups maximum. Every include, a, mx, exists and redirect costs at least one, nested includes count too, and ip4, ip6 and all cost nothing. Go over the limit and SPF returns permerror.
  • -all versus ~all: hard fail says unlisted sources aren't authorized; soft fail asks receivers to accept but mark the message. Microsoft recommends -all for Microsoft 365 domains, alongside DKIM and DMARC.
  • Don't flatten include:spf.protection.outlook.com into IP addresses; Microsoft's sending addresses change.

Third-party bulk senders are better placed on a subdomain such as marketing.contoso.com with its own SPF record. That protects your main domain's reputation and gives the subdomain its own lookup budget.

Step 2: Turn on DKIM signing for the custom domain#

  1. In the Microsoft Defender portal (security.microsoft.com), go to Email & collaboration › Policies & rules › Threat policies › Email authentication settings and open the DKIM tab.
  2. Try to switch the domain's toggle to Enabled. An error says the CNAME records are missing. That's expected: the keys now exist, so select OK.
  3. Click the domain row to open its details and copy the two values under Publish CNAMEs.
  4. At your DNS host, create two CNAME records with the hostnames selector1._domainkey and selector2._domainkey, each pointing to the value the portal gave you.
  5. Give Microsoft 365 a few minutes (sometimes longer) to detect them, then turn on Sign messages for this domain with DKIM signatures. The status should change to Signing DKIM signatures for this domain.

Watch out: copy the CNAME targets exactly rather than building them by hand. Domains added since May 2025 use a newer format such as selector1-contoso-com._domainkey.contoso.n-v1.dkim.mail.microsoft, where Microsoft assigns the letter before -v1. Older domains keep targets ending in .onmicrosoft.com.

Prefer PowerShell? The same values and switch are available in Exchange Online PowerShell:

PowerShell
Get-DkimSigningConfig -Identity contoso.com | Format-List Name, Enabled, Status, Selector1CNAME, Selector2CNAME
# If the domain isn't listed yet:
New-DkimSigningConfig -DomainName contoso.com -Enabled $false
# Once both CNAMEs resolve:
Set-DkimSigningConfig -Identity contoso.com -Enabled $true

Step 3: Roll out DMARC in stages#

Create a TXT record with the hostname _dmarc, starting in monitoring mode with aggregate reports:

Text
v=DMARC1; p=none; rua=mailto:dmarc-reports@contoso.com
  1. p=none: collect the aggregate reports (daily XML files, usually compressed) in a dedicated mailbox or a DMARC reporting service. Find every legitimate source and fix its SPF or DKIM alignment.
  2. p=quarantine: once the reports look clean, ask receivers to treat failures as suspicious. You can phase it in with pct=, for example 10, 25, 50, 75 and then 100.
  3. p=reject: the end goal, where failing mail is refused.

Microsoft suggests starting with low-volume subdomains and leaving the parent domain until last. Subdomains inherit the parent's policy unless they publish their own record, and each domain should have exactly one _dmarc record.

Verify with DNS and message headers#

First confirm the records resolve publicly:

PowerShell
Resolve-DnsName -Name contoso.com -Type TXT
Resolve-DnsName -Name selector1._domainkey.contoso.com -Type CNAME
Resolve-DnsName -Name _dmarc.contoso.com -Type TXT

Then send a message to a mailbox outside your organization (DKIM signing is skipped for mail that stays inside it) and view the headers. When the receiver is another Microsoft 365 tenant, a healthy result looks like this:

Text
Authentication-Results: spf=pass (sender IP is 198.51.100.25)
 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

The detail to check is header.d=contoso.com. If it shows any other domain, or DKIM reports none, signing with your custom domain isn't active yet. Microsoft's Message Header Analyzer makes long headers much easier to read.

Tips & gotchas#

  • A second SPF record added for a new SaaS tool is a common way to break SPF overnight. Merge it into the existing record.
  • SPF passes but DMARC fails for a third-party sender that uses its own domain as MAIL FROM. Set up DKIM at that service with your domain (d=contoso.com), or a custom return-path on your domain.
  • DNS host quirks: enter just selector1._domainkey as the hostname (most hosts append the domain), turn off proxying for the DKIM CNAMEs on DNS services that offer it, and create both selectors even though only one is active at a time.
  • Reports sent to another domain need that domain to publish an authorization record, such as contoso.com._report._dmarc with the value v=DMARC1;.
  • Parked domains that never send mail should get v=spf1 -all, a p=reject DMARC record and no DKIM records. If you don't send from your onmicrosoft.com domain, add a DMARC record for it too, under Settings › Domains in the Microsoft 365 admin center.

References#

Written and checked against current Microsoft Learn documentation. Test changes with a pilot group before rolling them out to everyone, and if an admin center path has moved since, search for the setting name instead.

Spotted a mistake, or did this fix work differently for you? Email me or message me on LinkedIn — corrections are credited in the article.

OE
Written by

Omer Eltayeb

Independent Microsoft Intune consultant in Cairo, Egypt, former Microsoft Cloud Solutions Architect, Microsoft Certified Trainer and Microsoft Innovative Educator Expert (2024–26) and Microsoft Elevate Educator Expert (2026–27). I share practical, step-by-step guides, study plans, scripts and toolkits for Microsoft Intune, Microsoft Entra ID, Microsoft Defender and Exchange Online with the community.

Microsoft Certified Trainer (MCT) 2026Microsoft Innovative Educator Expert 2025–2026Microsoft Elevate Educator Expert 2026–2027ISC2 Certified Information Systems Security Professional (CISSP)Microsoft 365 Certified: Enterprise Administrator Expert (MS-102)