CertaDNS

SPF, DKIM and DMARC for Microsoft 365

Set up email authentication on Microsoft 365: the SPF include, the two DKIM CNAMEs, and the onmicrosoft.com alignment trap that makes mail pass DKIM and fail DMARC.

Last reviewed . Admin consoles get reorganised — if a menu path below has moved, the record values are still correct.

Microsoft 365 will send mail for your domain the moment you add it, with no authentication configured beyond a default that does not align. Everything below is what you have to do on top, in the order it needs doing.

1. SPF

One include covers all of Exchange Online:

example.com.  IN  TXT  "v=spf1 include:spf.protection.outlook.com -all"

That include costs one DNS lookup and resolves to a flat list of ranges — no nested includes, which is more considerate than most providers:

$ dig +short TXT spf.protection.outlook.com
"v=spf1 ip4:40.92.0.0/15 ip4:40.107.0.0/16 ip4:52.100.0.0/15
  ip4:52.102.0.0/16 ip4:52.103.0.0/17 ip4:104.47.0.0/17
  ip6:2a01:111:f400::/48 … -all"
Checked on the review date. Microsoft changes these ranges; that is exactly why you reference the include rather than copying the addresses.

Do not add these ranges to your own record

Flattening this particular include is a bad trade. Microsoft revises the list, and a stale copy means some of your own Exchange Online mail starts failing SPF with no error anywhere. One lookup for the whole platform is cheap — spend it.

If you send from anywhere else — a marketing tool, a ticketing system, an application — add those includes to the same record. Two v=spf1 records is a permerror, not twice the capacity.

2. DKIM, and the alignment trap

This is the step that matters most, and the one most often skipped, because mail appears to work without it.

Out of the box, M365 signs your outbound mail with a key belonging to your tenant's onmicrosoft.com domain. That signature is valid. DKIM passes. And DMARC fails, because the signing domain is yourtenant.onmicrosoft.com and your From: header says example.com, which do not align.

At p=none you will never notice. At p=reject, with SPF as the only thing holding DMARC up, every forwarded message is rejected.

Publish the two CNAMEs

M365 does not give you a key to publish. It gives you two CNAMEs pointing into your tenant domain, and Microsoft holds the keys on the other end:

selector1._domainkey.example.com.  IN  CNAME
    selector1-example-com._domainkey.yourtenant.onmicrosoft.com.

selector2._domainkey.example.com.  IN  CNAME
    selector2-example-com._domainkey.yourtenant.onmicrosoft.com.
Note the domain is written with dashes for dots in the target label: example.com becomes example-com.

Microsoft's own domain is set up exactly this way, so you can see the shape in live DNS:

$ dig +short CNAME selector1._domainkey.microsoft.com
selector1-microsoft-com._domainkey.microsoft.onmicrosoft.com.

Your tenant name is the *.onmicrosoft.com domain listed under Microsoft 365 admin center → Settings → Domains.

Then turn it on

Publishing the CNAMEs is not sufficient. The signing has to be enabled in the portal, and it will refuse until the CNAMEs resolve:

Microsoft Defender portal → Email & Collaboration → Policies & rules → Threat policies → Email authentication settings → DKIM → select the domain → Enable

If it rejects the domain, the CNAMEs have not propagated yet or one of them has a typo. Both must resolve; one is not enough.

3. DMARC

Start at monitoring, with reporting on:

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com"

Leave it there until your aggregate reports show every legitimate sender passing, then move through quarantine to reject. The staged path covers what each stage is for.

Microsoft is a receiver too

M365 enforces inbound DMARC on mail arriving at your tenant, configurable under the same Email authentication settings. That is a separate decision from your own outbound policy, and worth reviewing at the same time.

4. Verify from outside

The portal showing DKIM as enabled means M365 believes it is signing. Confirm what the internet actually sees:

$ dig +short CNAME selector1._domainkey.example.com dig +short TXT selector1._domainkey.example.com dig +short TXT _dmarc.example.com
selector1-example-com._domainkey.yourtenant.onmicrosoft.com.
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ…"
"v=DMARC1; p=none; rua=mailto:dmarc@example.com"
The TXT query follows the CNAME and returns Microsoft's key. If it returns nothing, the CNAME is wrong or DKIM was never enabled in the portal.

Then send a message to an external address and read the headers. You want d=example.com in the DKIM-Signature. If it still says d=yourtenant.onmicrosoft.com, the enable step did not take.

The DKIM Inspector checks selector1 and selector2 by default, so it will find an M365 setup without being told the selector.

What M365 does differently

DKIM by CNAME, not by key. Almost every other provider generates a keypair and hands you a TXT record containing the public half. Microsoft keeps both halves and has you point at them. The practical consequence is good: rotation happens on Microsoft's side and your DNS never changes. The cost is that you cannot inspect or control the key, and you get two fixed selectors whether you want them or not.

The keys are 1024-bit. This is consistent across every tenant we checked, including Microsoft's own domain, GitHub's, and DuckDuckGo's — all on selector1 at 1024-bit RSA. RFC 8301 §3.2 treats 1024 as the floor and recommends 2048. It is not causing failures today, and it is not something you can change from your side.

MX shares the naming convention. example-com.mail.protection.outlook.com — same dashes-for-dots rule as the DKIM CNAME target, which is a useful thing to recognise when reading someone else's DNS.

Failure modes particular to M365

SymptomCauseFix
DMARC fails while DKIM shows passSigning with tenant.onmicrosoft.com — custom-domain DKIM was never enabledPublish both CNAMEs, then enable the domain in the Defender portal
The portal will not let you enable DKIMOne or both CNAMEs do not resolve yetCheck both with dig; allow for TTL after publishing
Some mail fails SPF after months of workingSomeone copied the spf.protection.outlook.com ranges into the record instead of using the includeReplace the literal ranges with the include
Mail from a distribution list or shared mailbox failsIt is being forwarded, so SPF breaks and only DKIM can carry DMARCCustom-domain DKIM. This is the case it exists for.
DKIM stops verifying after a tenant changeThe CNAME targets embed the tenant name; renaming or migrating the tenant invalidates themRepublish the CNAMEs against the new tenant domain

Honest limits

  • You cannot choose your DKIM key length or algorithm. 1024-bit RSA is what you get.
  • Two selectors, fixed names. If you need per-service selectors, they have to come from somewhere else.
  • The DKIM controls live in the Defender portal rather than the main admin center, which is why they are hard to find. Microsoft has moved this page more than once.
  • M365 does not host MTA-STS or provide DMARC report parsing. Both are separate problems once you get this far.

Nothing above needs CertaDNS — it is all records you publish wherever your DNS lives. Where we help is afterwards: the DMARC reports arrive as XML that is unreadable at volume, and the SPF record grows every time someone adds a sender. Email Authentication handles both.

Confirm it from outside

Microsoft 365 reporting its own state is not the same as the internet seeing it. Free, no account.

The protocols behind this

Other platforms