For a custom domain on Microsoft 365, publish an MX record whose value you copy from the Microsoft 365 admin center, an SPF TXT record v=spf1 include:spf.protection.outlook.com -all, two DKIM CNAME records at selector1._domainkey and selector2._domainkey whose targets are specific to your tenant, and a DMARC TXT record at _dmarc starting with p=none. The MX value and the DKIM targets cannot be guessed: read them in the admin center or the Defender portal, or with Get-DkimSigningConfig. Then switch DKIM signing on, and tighten DMARC step by step.
Which cloud are you in?
The SPF include depends on the Microsoft 365 environment, according to Microsoft’s SPF article:
| Environment | SPF record for a Microsoft-only domain |
|---|---|
| Microsoft 365 worldwide and GCC | v=spf1 include:spf.protection.outlook.com -all |
| GCC High and DoD | v=spf1 include:spf.protection.office365.us -all |
| Operated by 21Vianet | v=spf1 include:spf.protection.partner.outlook.cn -all |
The rest of this guide uses the worldwide value. Substitute your environment’s include where it appears.
Step 1: MX record
Add users and mailboxes first. Microsoft warns that after you change the MX record, all new mail for the domain goes to Microsoft 365, while existing mail stays at the old host unless you migrate it.
At your DNS host, the manual path in Microsoft’s documentation is:
| Field | Value |
|---|---|
| Type | MX |
| Host | @ |
| Points to | the value shown on the Add DNS records page in the admin center |
| Priority | the highest available, typically 0 |
| TTL | 3600 |
Microsoft says to copy the MX value from the admin center rather than construct it, because it is per tenant. If MX records for a previous provider exist, either delete them or give them a lower priority (a higher number) than Microsoft’s record. Microsoft also notes that Exchange Online supports only TTL values below 6 hours (21,600 seconds). In the admin center, the records are under Settings > Domains, your domain, DNS records. Check the result with the MX lookup.
Step 2: SPF record
Microsoft 365 has no portal or cmdlet for editing SPF; you create the TXT record at your DNS host.
@ TXT "v=spf1 include:spf.protection.outlook.com -all"
If an SPF record already exists, do not create a second one. Microsoft says to add its include to the existing record, so that a single record covers the old provider and Microsoft 365. Two v=spf1 records cause permerror.
Combining with other senders. On-premises servers go in as ip4: or ip6:; other services as include:. Microsoft’s article shows this pattern for a domain with an on-premises server (the address here is a documentation placeholder):
@ TXT "v=spf1 ip4:192.0.2.10 include:spf.protection.outlook.com -all"
Microsoft recommends a subdomain (for example marketing.example.com) for bulk services you do not control. Each subdomain that sends needs its own SPF record, and each gets its own 10-lookup budget.
The 10-lookup limit. Each include:, a, mx, exists and redirect counts as one lookup, and nested includes add more; ip4: and ip6: do not count. Going over produces permerror and may produce a bounce. Microsoft’s article warns against flattening spf.protection.outlook.com into IP addresses, because its addresses change frequently. See SPF has too many DNS lookups for the full treatment and verify with the SPF checker.
-all versus ~all. Microsoft recommends -all because DKIM and DMARC are also in place. Its note: DMARC treats both as SPF failures, but the DMARC policy is effectively ignored for SPF ~all failures if the message has no DKIM signature. If you are still discovering senders, ~all is the safer interim choice; move to -all when your DMARC reports are clean. Use ?all only for testing.
Step 3: DKIM
Without configuration, Microsoft signs with your *.onmicrosoft.com domain, which does not align with your own From domain. For a custom domain you publish two CNAME records. Microsoft generates two key pairs and the CNAMEs point at the public keys. The selectors are named selector1 and selector2.
Get the targets. The CNAME targets have the form selector1-<your-domain-with-dashes>._domainkey.<tenant>.<partition>-v1.dkim.mail.microsoft, and Microsoft states that the examples in its article are for illustration only. Read your real values in the Defender portal:
- Go to https://security.microsoft.com/authentication and open the DKIM tab (Email & collaboration > Policies & rules > Threat policies > Email authentication settings).
- Select your domain. Per Microsoft’s procedure, toggling signing on before the records exist produces an error and sets the status to
CnameMissing; the domain flyout then shows the values under Publish CNAMEs.
Or in Exchange Online PowerShell:
Get-DkimSigningConfig -Identity example.com | Format-List Name,Enabled,Status,Selector1CNAME,Selector2CNAME
Publish the records:
selector1._domainkey CNAME <Selector1CNAME value>
selector2._domainkey CNAME <Selector2CNAME value>
Wait, then enable. Microsoft says detection takes a few minutes or possibly longer. After that, open the domain flyout and turn on Sign messages for this domain with DKIM signatures, or run Set-DkimSigningConfig -Identity example.com -Enabled $true. If the CNAMEs are not detected, you get an error that repeats the expected values; check for typos in dashes, periods and underscores. A healthy domain shows Enabled: True and Status: Valid, and the DKIM-Signature header of outbound mail shows d=example.com with s=selector1-example-com or the selector 2 equivalent.
Key size. Per Microsoft’s article, the KeySize parameter defaults to 1024; 2048 is available through New-DkimSigningConfig -KeySize 2048 or when rotating: Rotate-DkimSigningConfig -Identity example.com -KeySize 2048. A rotation is not immediate: the new key starts signing after four days (96 hours).
Step 4: DMARC
Microsoft requires SPF and DKIM first, and DKIM must sign with the custom domain so the signing domain aligns with the From domain. There is no admin-center setting for custom domains; create the record at your DNS host. Start in monitoring mode:
_dmarc TXT "v=DMARC1; p=none; pct=100; rua=mailto:[email protected]"
Microsoft recommends a gradual rollout: p=none, then p=quarantine, then p=reject, with pct stepping through 10, 25, 50, 75 and 100 if you want to limit exposure. Start with a subdomain of low volume if you have one, and leave the parent domain for last. Subdomains inherit the parent record unless they publish their own.
Trade-offs specific to reject and quarantine: Microsoft notes that outbound mail from your domain that fails DMARC at the destination is routed through the high-risk delivery pool when the policy is p=reject or p=quarantine, with no override. And forwarded mail and mailing lists often fail SPF and break DKIM, so some false positives are expected. Use a dedicated mailbox or group for rua reports. Microsoft 365 does not send forensic (ruf) reports, so do not rely on them. If a service passes SPF and DKIM yet DMARC fails, read DMARC fails even though SPF and DKIM pass.
If you own a domain that never sends mail, Microsoft’s parked-domain values are v=spf1 -all and v=DMARC1; p=reject;.
Step 5: Verify
- MX lookup: the Microsoft host only, no older provider at lower numbers.
- SPF checker: one record, correct include for your cloud, lookups at or under 10.
- DMARC checker: one record at
_dmarc,ruapresent. - Send a message to an outside mailbox and paste its headers into the email header analyzer.
spf=pass,dkim=pass header.d=example.comanddmarc=passis the target.
All records at a glance
| Host | Type | Value |
|---|---|---|
@ | MX | copy from the admin center, priority 0 |
@ | TXT | v=spf1 include:spf.protection.outlook.com -all |
selector1._domainkey | CNAME | Selector1CNAME from Defender portal or PowerShell |
selector2._domainkey | CNAME | Selector2CNAME from Defender portal or PowerShell |
_dmarc | TXT | v=DMARC1; p=none; pct=100; rua=mailto:[email protected] |
Common mistakes
- Typing the Microsoft documentation’s example CNAME targets instead of your tenant’s values.
- A trailing period or a space inside the include: Microsoft lists
include:spf.protection.outlook.com.,include=andinclude:as invalid. - Using the worldwide include on a GCC High or 21Vianet tenant.
- Keeping an old SPF record next to the new one.
- Publishing DKIM CNAMEs on parked domains; Microsoft does not recommend them there.
- Moving to
p=rejectbefore reading the aggregate reports.
FAQ
Do I need DKIM if SPF passes?
Yes. DMARC needs one aligned pass, and forwarding breaks SPF. Microsoft’s default onmicrosoft.com signature does not align with your custom From domain.
Why does Microsoft recommend -all while some guides say ~all?
Microsoft’s reasoning is that DMARC and DKIM handle the enforcement. If you have not yet identified every sender, ~all limits the damage of a missed one.
Can I manage these records inside Microsoft 365? For custom domains, not SPF or DMARC: Microsoft says there are no portals or cmdlets for them. The admin center can add its standard DNS records automatically only if your registrar supports Domain Connect; otherwise you add them manually.
Sources
- Microsoft Learn, set up SPF: https://learn.microsoft.com/en-us/defender-office-365/email-authentication-spf-configure
- Microsoft Learn, DKIM for your custom domain: https://learn.microsoft.com/en-us/defender-office-365/email-authentication-dkim-configure
- Microsoft Learn, set up DMARC: https://learn.microsoft.com/en-us/defender-office-365/email-authentication-dmarc-configure
- Microsoft Learn, connect your domain by adding DNS records: https://learn.microsoft.com/en-us/microsoft-365/admin/get-help-with-domains/create-dns-records-at-any-dns-hosting-provider
- RFC 7208 section 4.6.4, DNS lookup limits: https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4
- RFC 7489 section 6.3, DMARC record tags: https://www.rfc-editor.org/rfc/rfc7489#section-6.3