oeltayeb.com · Exchange Online Toolkit

Checklist

SPF/DKIM/DMARC setup checklist

Based on the article: SPF, DKIM and DMARC for your Microsoft 365 custom domain: a practical setup guide · 5 min read

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 it works

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.

  • 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.

Checklist

  1. 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:

    v=spf1 include:spf.protection.outlook.com -all
    • 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.
  2. 2

    Turn on DKIM signing for the custom domain

    • In the Microsoft Defender portal (security.microsoft.com), go to Email & collaboration › Policies & rules › Threat policies › Email authentication settings and open the DKIM tab.
    • 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.
    • Click the domain row to open its details and copy the two values under Publish CNAMEs.
    • 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.
    • 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
  3. 3

    Roll out DMARC in stages

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

    v=DMARC1; p=none; rua=mailto:dmarc-reports@contoso.com
    • 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.
    • 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.
    • p=reject: the end goal, where failing mail is refused.

Verify

  • 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:
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.

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.

Microsoft Learn references