Checked against the official documentation on

Set up SPF, DKIM and DMARC for Microsoft 365 on Cloudflare

Four records, all on the DNS Records page of your Cloudflare dashboard. SPF is a fixed line you can copy straight from this page. DKIM is two CNAME records whose targets only Microsoft can give you — they're generated for your tenant, and nobody can publish them in advance. DMARC is a line you write yourself, starting at p=none.

The one Cloudflare-specific trap is the orange cloud: both DKIM CNAMEs are created proxied by default, and a proxied CNAME hides Microsoft's hostname behind a Cloudflare IP address. Microsoft's own DKIM article now carries a Cloudflare section saying exactly that. Switch both records to DNS only the moment you create them, and this setup is one of the fastest in our corpus — Cloudflare changes are live within minutes.


These records let receiving mail servers check that a message claiming to be from you really is from you. They do not guarantee your email reaches the inbox — your content and sending reputation matter at least as much — but without them, anyone can send email in your name.

What we don't do: we never touch your DNS zone. We read, we prescribe, you paste. You're the one who saves it, in your own account, with your own credentials.


Before anything else: is Cloudflare actually your DNS?

Cloudflare only answers for your domain if your nameservers point to Cloudflare. A domain bought elsewhere and never re-delegated can have a perfectly filled-in Cloudflare zone that nobody on the internet ever consults. Symptom: you add the records, the Defender portal stays on CnameMissing, and you redo them three times thinking you mistyped.

Check where your domain delegates first. If it isn't Cloudflare, the values below don't change — only the panel does.


The records to copy and paste

1. SPF — who is allowed to send as you

Cloudflare field Value
Type TXT
Name @ (the at sign — it means your root domain)
Content v=spf1 include:spf.protection.outlook.com -all
TTL Auto (or 1 hour — see below)
Proxy status (not shown — TXT records can't be proxied)

What you must replace: nothing, if Microsoft 365 is your only sender. This is Microsoft's published value, and Cloudflare's own troubleshooting table lists the same line for Microsoft 365. If Microsoft 365 was set up through its wizard, this record may already exist — look at the table before you add anything, and Edit rather than add.

On -all versus ~all. Microsoft recommends the strict version and explains why: "For Microsoft 365 domains, we recommend -all (hard fail) because we also recommend DKIM and DMARC for the domain." It also corrects a widespread belief: "DMARC treats -all (hard fail) and ~all (soft fail) as SPF failures." The soft version doesn't buy you any leniency from DMARC — the difference only matters to servers that check SPF without DMARC.

If other services send on your behalf, they all go in one single line:

v=spf1 include:spf.protection.outlook.com include:spf.example-crm.com -all
Also sending for you? What to add
Mailchimp (nothing — Mailchimp doesn't ask for SPF)
SendGrid (nothing on the root domain in its default mode)
HubSpot the include: shown in your HubSpot settings
Cloudflare Email Routing include:_spf.mx.cloudflare.net — see the warning below
Your CRM, invoicing tool, newsletter tool the value shown in their interface

⚠️ One SPF record per domain. Always — and you edit the existing line, you never add a second one. Microsoft: "only one SPF record is allowed per domain or subdomain" and "Multiple SPF TXT records for the same domain or subdomain cause SPF to return permerror". Same ceiling on lookups: "If the number of DNS lookups… is greater than 10, the message fails SPF with a permanent error." Every include: costs at least one.

⚠️ Cloudflare can write a second SPF for you without asking. Enabling Email Routing (under ComputeEmail ServiceEmail Routing) publishes v=spf1 include:_spf.mx.cloudflare.net ~all on your root domain — and its own MX records, which Cloudflare warns "may conflict with your provider's records". Email Routing forwards mail for a domain without mailboxes; Microsoft 365 is your mailboxes. If you really need both, merge into one line — Cloudflare's instruction is "If you have existing SPF records, merge them"; otherwise turn Email Routing off.

On TTL: Microsoft recommends "a minimum TTL value of 3600 seconds (one hour) on SPF TXT records to avoid DNS lookup timeouts". Cloudflare's Auto is 300 seconds, and for DNS-only records the picker goes "between 30 seconds (Enterprise) or 60 seconds (non-Enterprise) and 1 day" — so you can select 1 hour if you want to follow Microsoft literally. Either works; the shorter one just makes your next edit visible faster.

2. DKIM — two CNAMEs, and the values are yours alone

Cloudflare doesn't generate your DKIM key. Microsoft does, and it publishes it on its own servers — you only create two CNAME records pointing at it. Nothing is signed until you do: Microsoft says "Currently, no DKIM signing occurs for outbound mail from custom domains".

Cloudflare field Record 1 Record 2
Type CNAME CNAME
Name selector1._domainkey selector2._domainkey
Target selector1-YOUR-DOMAIN-WITH-DASHES._domainkey.YOUR-TENANT.X-v1.dkim.mail.microsoft selector2-YOUR-DOMAIN-WITH-DASHES._domainkey.YOUR-TENANT.X-v1.dkim.mail.microsoft
Proxy status DNS only (grey cloud) DNS only (grey cloud)
TTL Auto (or 1 hour) Auto (or 1 hour)

Those two Targets are models, not values. Replace both entirely — and not by hand. Microsoft's own template is selector1-<CustomDomainWithDashes>._domainkey.<InitialDomainPrefix>.<DynamicPartitionCharacter>-v1.dkim.mail.microsoft, where YOUR-TENANT above is your initial domain prefix (the part before .onmicrosoft.com) and X is that dynamically assigned character — "for example, r or n" — introduced in May 2025. Microsoft is explicit: it "is automatically assigned by Microsoft when you add a new custom domain and enable DKIM. The value is determined by Microsoft's internal routing logic and isn't configurable." You cannot derive it from your domain name.

So you copy both values from the Defender portal — the click path is below — or from PowerShell:

Get-DkimSigningConfig -Identity YOUR-DOMAIN.com | Format-List Name,Enabled,Status,Selector1CNAME,Selector2CNAME

Domains added before May 2025 keep the older shape, selector1-YOUR-DOMAIN-WITH-DASHES._domainkey.YOUR-TENANT.onmicrosoft.com — also a model, not a value. Both formats are live in the world today, and "The old and new formats can't coexist for the same selector." Whatever the portal shows you is the right one for your domain, and you don't get to mix them.

⚠️ Grey cloud, both records — the two vendors say it independently. Microsoft, in the Cloudflare section of its DKIM article: "Disable the Cloudflare proxy (orange cloud) for DKIM CNAME records. DKIM CNAME records must resolve directly to the Microsoft DKIM infrastructure. If the proxy is enabled, DNS lookups return Cloudflare's IP addresses instead of the CNAME target, and DKIM verification fails. Set the proxy status to DNS only (gray cloud icon)." Cloudflare, from its side: "Proxying is on by default when you onboard a domain via the dashboard", and "Only A, AAAA, and CNAME records that serve HTTP or HTTPS traffic can be proxied" — which is exactly what these two records are.

One nuance worth knowing. Cloudflare keeps a list of CNAME targets it refuses to proxy, because "Cloudflare is purposely preventing that record from being proxied to protect you from a misconfiguration". That list includes any subdomain of onmicrosoft.com — the old Microsoft format. The new dkim.mail.microsoft targets are still not on it as of 17 September 2026. So a domain added before May 2025 gets a safety net; a domain added since gets an orange cloud unless you set it grey yourself.

CNAME flattening is the other thing that can break these two. Cloudflare's troubleshooting page: "Some email providers require CNAME records for features like DKIM authentication or autodiscover. When CNAME flattening is turned on — either globally for all CNAME records or individually on a specific record — the CNAME is flattened to an A record, which can prevent email providers from reading the record correctly." The zone-wide switch is DNS SettingsCNAME flattening for all CNAME records, available on paid plans; the per-record version is the Flatten option inside a record's Edit panel. If either is on for your selectors, the Defender portal will never see them.

3. DMARC — the instruction you give to inboxes

Cloudflare field Value
Type TXT
Name _dmarc
Content v=DMARC1; p=none; rua=mailto:YOU@YOUR-DOMAIN.com
TTL Auto

What you must replace: YOU@YOUR-DOMAIN.com with an address you actually read. Microsoft's advice on which one is good: "Create a shared mailbox (for example, dmarc-reports@contoso.com). Don't use individual user mailboxes." A DMARC record without a rua= is a report you'll never see.

Why p=none first. It means "watch and tell me". Nobody gets blocked, nothing changes for your recipients, and you start receiving a list of everything sending in your name — including the tools you'd forgotten about. Microsoft's rollout plan opens the same way: "Start with a DMARC policy of p=none and monitor the results for the domain", then "Go slowly and methodically deal with issues that are revealed in DMARC reporting." You watch for two to four weeks, confirm every legitimate sender is recognised, and only then tighten one notch to p=quarantine, then p=reject.

⚠️ Don't copy Microsoft's DMARC example as-is — it's a bad example, and here's why we say so. Its documented records are v=DMARC1; p=none; pct=100; rua=mailto:…; ruf=mailto:… and the same line at p=quarantine, with a ramp of pct=10, 25, 50, 75, 100. pct= was removed from the DMARC standard by RFC 9989, published in May 2026. Servers following the current standard ignore it, so pct=10 doesn't give you a cautious 10 % rollout — it gives you your full policy on everyone while you believe you're easing in. Microsoft's staged idea is right; only the mechanism is obsolete. Ramp with the policy itself: none, then quarantine, then reject. Our value above has no pct= in it, and that's deliberate.

⚠️ One DMARC record per domain too — you edit the existing one. If a _dmarc record already exists — because you enabled Cloudflare's DMARC Management, which offers to create one — you Edit it rather than adding a second. And note that DMARC Management, when it finds an existing record, "will add another rua… entry to it" pointing at a Cloudflare address: your own address stays, Cloudflare gets a copy. That's fine, as long as yours is in there.

One record Cloudflare can't hold for you. Microsoft asks you to publish a DMARC record on domains you don't send from, so nobody else can: "If you own registered domains that aren't used for email or anything at all (also known as parked domains), configure the DMARC TXT records in those domains to specify no email should ever come from those domains. This directive includes the *.onmicrosoft.com domain if you aren't using it for email." That last one lives in a zone Cloudflare doesn't hold — you create it in the Microsoft 365 admin center: "select Show all > Settings > Domains". Different zone, different panel.


The click path

In Microsoft Defender — get your two DKIM values

  1. Sign in to the Defender portal at security.microsoft.com and go to Email & collaborationPolicies & rulesThreat policiesEmail authentication settings — or go straight to security.microsoft.com/authentication.
  2. Open the DKIM tab. Your domain shows Disabled with the status NoDKIMKeys.
  3. Try to slide the Toggle to Enabled. Microsoft's own instruction, and it looks like a bug the first time: "A Client error dialog opens. The error contains the required values to use in the two CNAME records… along with a lot of other text." Select OK.
  4. The status is now CnameMissing. Click the row to open the domain's details flyout, and in the Publish CNAMEs section select Copy. Leave this flyout open — you'll come back to it.

Some tenants show Create DKIM keys at the bottom of the flyout instead; it produces the same two values.

In Cloudflare — create the four records

  1. Sign in to the Cloudflare dashboard, select your account, then your domain.
  2. Go to the DNS Records page.
  3. Look at the table first. Is there already a TXT on @ starting with v=spf1? A _dmarc record? If so, you'll Edit, not add.
  4. Select Add record, choose the TypeCNAME for the two DKIM records, TXT for SPF and DMARC.
  5. Fill in Name and the value field — it's called Target for a CNAME, Content for a TXT.
  6. For the two CNAMEs, set Proxy status to DNS only — the cloud must be grey, not orange. TXT records don't show this field.
  7. Leave TTL on Auto (or pick 1 hour), then Save. Repeat.

Two vendors, two routes to the same screen — don't let it stall you. Cloudflare's docs say "In the Cloudflare dashboard, go to the DNS Records page" then "Select Add record". Microsoft's DKIM article says "Select your domain (contoso.com) > DNS > Records" then "Select Add record". Microsoft's separate Cloudflare page for the admin center, last updated 16 June 2026, still describes an older route: "On the Account Home page, find the domain that you want to update, select the three dots (...) at the right and select Configure DNS from the drop-down menu", then +Add record. All three land on the same list of records. Follow Cloudflare's wording; it's the one its own product matches.

The Name field wants the relative name. Cloudflare: "To create a zone apex record, use @ for the record Name." Type selector1._domainkey, _dmarc, @ — never selector1._domainkey.yourdomain.com; Cloudflare completes the rest. Leading underscores are fine: "Underscores are valid in DNS and commonly used for service records."

Cloudflare's wizard, and what it can't do. Cloudflare's docs recommend its Email security Wizard over hand-typed TXT records: "You could also use TXT to create email authentication records, but we recommend that you use our Email security Wizard instead." It lives at EmailDMARC ManagementEmail record overviewView records, and "will also list any previous records you might already have in your account" — a good way to catch a forgotten SPF or DMARC. What it cannot do is produce Microsoft's DKIM CNAMEs: those exist only in the Defender portal. Whichever route you take for SPF and DMARC, DKIM is two Microsoft values pasted into two grey-clouded CNAMEs.

Back in Defender — switch signing on

Return to the flyout you left open and select the Sign messages for this domain with DKIM signatures toggle. Microsoft: "It takes a few minutes (or possibly longer) for Microsoft 365 to detect the new CNAME records you created", then a dialog says "It may take several minutes to synchronize the status change." When it works, the toggle reads Enabled, the status reads Signing DKIM signatures for this domain, and Rotate DKIM keys appears.

If instead you get another Client error, Microsoft's checklist is the right one: "Check for typos in the values at the domain registrar (easy to do with the dashes, periods, and underlines!), wait a while longer, and then run the command again." On Cloudflare, add one item to that list before anything else: is the cloud grey?


The 3 mistakes we see most often here

1. An orange cloud on selector1._domainkey — or on autodiscover

This is the Cloudflare × Microsoft 365 mistake, and Microsoft's own Cloudflare setup page for the admin center makes it more likely: that page walks you through the verification TXT, the MX, the autodiscover CNAME and SPF without once mentioning proxy status. Follow it in the default dashboard and your autodiscover CNAME is born orange — Outlook can no longer auto-configure mailboxes. Then you reach DKIM, and the same thing happens to both selectors.

Cloudflare lists the exposed hostnames itself: "mail.example.com used for SMTP, IMAP, or POP3… Any hostname targeted by your MX record… Autodiscover or mail service hostnames that must return the provider's actual DNS target." Your MX target (…mail.protection.outlook.com) is Microsoft's own hostname and can't be proxied from your zone — "Your MX record itself is always DNS-only" — so the MX is safe. The CNAMEs are not.

How you spot it: the Defender portal stays on CnameMissing and throws a Client error on a value you copied with the Copy button; in the DNS Records table, the record shows an orange cloud. For autodiscover: Outlook asks for server settings it used to find on its own.

The fix: Edit the record, switch Proxy status to DNS only, Save. Then retry the toggle in Defender.

2. Copying a DKIM target from a tutorial — or regenerating it "to see"

Any page that hands you selector1-yourdomain-com._domainkey.yourtenant.onmicrosoft.com as a value to type is describing the pre-May 2025 format — correct for domains added before then, wrong for everyone since, and impossible to adapt by hand because of the assigned character. And when the first attempt fails, people rotate keys "to see": rotation "isn't immediate. It takes four days (96 hours) for the new private key to start signing messages", so you've now added a delay to a record that was probably just orange.

How you spot it: CnameMissing persists while your two CNAMEs are visibly there and grey; an outside lookup of selector1._domainkey.yourdomain.com returns a target that doesn't match what the flyout shows.

The fix: open the flyout, Copy, paste over the existing Targets. Never a value from a guide — including this one, which gives you a model, not a value.

3. Stopping where Microsoft's Cloudflare page stops

Microsoft's "Connect your DNS records at Cloudflare to Microsoft 365" article covers the verification TXT, MX, autodiscover, SPF and the Teams SRV records — then ends. Neither DKIM nor DMARC appears on it. Its Domain Connect shortcut ends on "Your domain setup for Microsoft 365 is complete." What's complete is mail flow and SPF. Follow that page to the letter and you finish with one record out of three — and Microsoft's SPF article says so plainly: "SPF alone is not enough."

How you spot it: mail works, the wizard said complete, and a scan shows no selector1._domainkey, no selector2._domainkey and no _dmarc.

The fix: treat the wizard as step one. DKIM is section 2 above; DMARC is section 3.

⚠️ Don't confuse the Name trap with its mirror image. Pasting a full hostname into Cloudflare's Name field publishes selector1._domainkey.yourdomain.com.yourdomain.com, and the fix is to shorten it. At some other hosts (OVH, Gandi), the symmetrical trap sits on a CNAME target, where the fix is to add a trailing dot. Cloudflare's Target field takes Microsoft's value as-is. Same look, opposite fixes.


How long before it takes effect

  • In Cloudflare: saved immediately. Cloudflare's DNS FAQ: changes "take effect globally within 5 minutes, usually much less"; its Email Service docs are more cautious — "DNS changes can take up to 24 hours to propagate globally, but usually complete within 5-15 minutes for domains using Cloudflare DNS". Microsoft's Cloudflare page says "about 15 minutes". Fast, by any of the three.
  • The old value can stay cached for as long as the TTL you had set before the change — five minutes on Auto, one hour if you followed Microsoft's SPF advice, up to a day if you had set one.
  • For the Defender portal to see your CNAMEs: "a few minutes (or possibly longer)". Microsoft publishes no fixed figure for DKIM activation — don't trust a guide that gives you one.
  • After a DKIM key rotation: "four days (96 hours)" before the new key signs.
  • For DMARC reports: the first ones arrive 24 to 72 hours after you publish, then roughly once a day. Cloudflare's DMARC Management says the same: "it may take up to 24 hours to receive your first DMARC report".

Frequently asked questions

Why does Microsoft say CnameMissing when both CNAMEs are right there?

Almost always the orange cloud. A proxied CNAME returns Cloudflare's IP addresses instead of Microsoft's target, so Defender never sees your selectors. Edit each record, set Proxy status to DNS only, save, then retry the toggle. If both clouds are already grey, check CNAME flattening next.

Can I just copy the selector1 CNAME value from this page?

No. Since May 2025 Microsoft's target contains a character it assigns to your tenant, and it "isn't configurable" — nobody can predict it. The tables here are models. Take your two real values from the Defender portal's Publish CNAMEs section, or from the PowerShell command above.

How long before Microsoft 365 sees the records?

Cloudflare publishes changes "within 5 minutes, usually much less". Microsoft then takes "a few minutes (or possibly longer)" to detect the CNAMEs, and publishes no fixed figure for DKIM activation. Old values can stay cached for the length of the TTL you had set before the change.


Further reading

Check that it worked

Enter your domain and we'll show you what the rest of the world sees: SPF, DKIM, DMARC, and what's off. Free, no account, results in 20 seconds.