17 June 2026 · 14 min read
Cloudflare is, for most people, the easiest place to publish DMARC, SPF and DKIM correctly, and it is also one of the easiest to get subtly wrong. The DNS editor is friendly, it does TXT chunking and apex CNAME flattening for you, and TTL is one click. But that same helpfulness hides a few behaviours that surprise people: the orange cloud that should never touch these records, the way the Name field auto-appends your domain, the proxy interaction with Email Routing, and the moment Cloudflare flattens a CNAME at the root into A records and quietly changes what your DKIM lookup returns. This guide is written specifically for the Cloudflare dashboard and the Cloudflare DNS editor. It is not a generic "what is DMARC" explainer; if you need that grounding first, read What is DMARC, What is SPF and What is DKIM, then come back here to publish.
Everything below assumes Cloudflare is your authoritative DNS, meaning your domain's nameservers at the registrar point to Cloudflare (the *.ns.cloudflare.com pair). If you only use Cloudflare for CDN in front of another DNS host, the records must go on whichever provider is authoritative, not here. You can confirm where your DNS actually lives with the DNS record checker before you start.
Before you touch anything: confirm the zone is authoritative
Open the Cloudflare dashboard, pick the domain, and look at the DNS then Records screen. At the top Cloudflare tells you the nameservers it expects and whether the zone is Active. Two states matter:
- Full setup (Active). Cloudflare is authoritative. Records you add here are what the internet resolves. This is what you want for DMARC, SPF and DKIM.
- Partial (CNAME) setup. Cloudflare is only proxying specific hostnames and your real DNS is elsewhere. In this mode the records you need will not be served from Cloudflare. Publish them at your authoritative host instead.
If the zone is Active, you are good. Run a baseline before changing anything so you can compare afterwards: check your current policy with the DMARC checker, your sending record with the SPF checker, and your signatures with the DKIM checker. Knowing the "before" state stops you chasing a problem that was already there.
The three records and where they live
The single most common publishing mistake on any host is putting the right value at the wrong name. Fix the target names in your head first.
- SPF is one TXT record at the root of your domain. On Cloudflare you enter
@in the Name field, which Cloudflare displays back to you as your bare domain (example.com). The value starts withv=spf1. You must have exactly one SPF record; two is a permanent error. - DMARC is one TXT record at the subdomain
_dmarc. You enter_dmarcin the Name field, and Cloudflare turns that into_dmarc.example.com. The value starts withv=DMARC1. - DKIM is published per selector at
selector._domainkey. You enter something likes1._domainkeyorgoogle._domainkeyin the Name field, givings1._domainkey.example.com. The value is either a long TXT public key, or a CNAME pointing at your sending platform's hosted key, depending on the platform.
Two rules apply to every record you add in the Cloudflare editor:
- Enter the prefix only in Name, never the full name. Cloudflare appends the zone for you. If you type
_dmarc.example.comin Name, you create_dmarc.example.com.example.com, which resolves to nothing. Type only_dmarc,@, ors1._domainkey. (Cloudflare is good about showing you the resulting full name as you type, so watch that preview.) - Underscores are literal and mandatory.
_dmarcand_domainkeykeep their leading underscore. Cloudflare handles them fine; the mistake is people dropping the underscore, not the editor rejecting it.
Adding a record in the Cloudflare DNS editor, step by step
The mechanics are the same for all three record types:
- Go to DNS then Records and click Add record.
- Pick the Type:
TXTfor SPF and DMARC, and eitherTXTorCNAMEfor DKIM depending on your platform. - In Name, enter the prefix only (
@,_dmarc, orselector._domainkey). - In Content (TXT) or Target (CNAME), paste the value. For TXT, paste it as one continuous line with no surrounding quotes. Cloudflare adds the quoting and any chunking internally.
- Leave TTL on Auto.
- For a CNAME, set Proxy status to DNS only (the grey cloud). This is the setting that trips people up; more on it below.
- Click Save.
Concrete examples, entered exactly as shown.
DMARC, starting at monitoring policy. Type TXT, Name _dmarc, Content:
v=DMARC1; p=none; rua=mailto:dmarc-rua@example.com; fo=1; adkim=s; aspf=s
SPF for a domain sending through Google Workspace plus one marketing tool. Type TXT, Name @, Content:
v=spf1 include:_spf.google.com include:servers.mcsv.net -all
DKIM as a CNAME (the common case for Google Workspace, Amazon SES, and most platforms that host the key for you). Type CNAME, Name google._domainkey, Target:
google._domainkey.example.com -> (the host your provider gives you)
DKIM as a TXT public key (when you generate the key yourself). Type TXT, Name s1._domainkey, Content is the full v=DKIM1; k=rsa; p=MIIBIjANBgkq... string on a single line.
If you do not yet have the DMARC value worked out, build one with the DMARC generator and assemble SPF with the SPF generator so you start from a syntactically valid string.
The orange cloud: keep these records on DNS only
Cloudflare's flagship feature is its proxy, shown as an orange cloud next to A, AAAA and CNAME records. When a record is proxied (orange), Cloudflare answers DNS for that hostname with its own anycast IP addresses and sits in the traffic path. That is exactly what you want for a website. It is exactly what you do not want for authentication records.
- TXT records cannot be proxied at all. SPF and DMARC are TXT, so the orange cloud never appears for them. There is nothing to get wrong here.
- DKIM CNAMEs must stay grey (DNS only). A DKIM lookup is a DNS resolution of
selector._domainkey.example.comto find the public key. If you proxy that CNAME, Cloudflare returns its proxy addresses instead of resolving through to your provider's key host, and the verifier cannot retrieve the key. DKIM then fails. Always set DKIM CNAMEs to DNS only.
The same principle applies to any other CNAME involved in authentication: a custom MAIL FROM / return-path host, an MTA-STS policy host, or a BIMI logo reference. Keep all of them grey. The orange cloud is for web traffic, not for the records receivers look up to verify your mail.
CNAME flattening at the root, and why it matters for SPF and DKIM
Cloudflare has a feature called CNAME flattening. Because the DNS standard forbids a CNAME at the zone apex (the root example.com) when other records exist there, Cloudflare lets you add a root CNAME anyway and "flattens" it: at query time it follows the CNAME and returns the resolved A/AAAA records directly. This is genuinely useful for pointing your apex at a hosted app. It has two consequences worth understanding for authentication.
- SPF is unaffected in practice, but do not try to CNAME your SPF. SPF lives in a TXT record, not a CNAME, so flattening does not apply to it. The trap is people who try to "delegate" SPF by CNAMEing the root to another provider's record. That breaks: a CNAME at the apex cannot coexist with the TXT records you need, and Cloudflare's flattening only resolves address records, not the TXT your SPF needs. Publish SPF as a plain TXT at
@. - DKIM CNAMEs are not at the apex, so they are not flattened. DKIM lives at
selector._domainkey, a subdomain, where ordinary CNAME rules apply and flattening does not kick in. The CNAME resolves normally to your provider's key host (as long as it is grey, per the section above). So for standard DKIM you do not need to think about flattening at all; you only meet it if you deliberately CNAME the root.
By default Cloudflare sets CNAME flattening to "Flatten CNAME at root" only, which is the safe setting. You can find it under DNS then Settings. Leave it alone unless you have a specific reason; the default does not interfere with mail authentication.
TXT chunking: long DKIM keys on Cloudflare
A 2048-bit DKIM public key in a TXT record is longer than 255 characters, and a single DNS character-string is capped at 255 bytes. On many DNS hosts you have to manually split the value into quoted 255-character chunks, like "v=DKIM1; k=rsa; p=MII..." "...rest of key...". Get the split wrong and the key is corrupted.
On Cloudflare you do not do this manually. Paste the entire v=DKIM1; ... p=... value as one unbroken line into the Content field, with no quotes and no manual splits. Cloudflare stores it and serves it as the correctly chunked multi-string TXT record automatically. If you paste pre-split, pre-quoted chunks, you will usually end up with literal quotation marks inside the value and a broken key. So: one line, no quotes, let Cloudflare handle the rest.
After saving, confirm the key actually resolves and parses with the DKIM checker. Cloudflare saying "saved" only means the record exists, not that the key is valid or that you pasted the whole thing. A truncated paste is the classic cause of a DKIM record that exists but fails verification. For background on why the chunk boundary matters and how selectors work, see DKIM selectors explained.
TTL on Cloudflare: leave it on Auto, except briefly during a rotation
TTL (time to live) is how long resolvers cache a record. Cloudflare offers Auto plus fixed values from 1 minute up to a day.
- Auto is the right default for SPF, DMARC and DKIM. Cloudflare uses a sensible short TTL (around 5 minutes for proxied records, and a reasonable value for DNS-only records), which means your changes propagate quickly without you micromanaging it.
- Lower the TTL before a planned change, not after. TTL only governs how long the old value is cached. If you are about to rotate a DKIM key or tighten an SPF record and you want fast cutover, set the TTL to 1 minute, wait for the old TTL to expire, then make the change. Lowering it at the same moment you change the record does nothing for the already-cached old value.
- Cloudflare changes are fast at the edge but resolvers still cache. Even with a 1-minute TTL, a resolver that fetched the record 4 minutes ago under a longer TTL will hold the stale value until its own cache expires. Check propagation with the DNS propagation checker rather than assuming "saved on Cloudflare" equals "live everywhere".
This matters most for DKIM key rotation, where overlapping old and new selectors avoid a signing gap. We cover the overlap technique in DKIM key rotation.
SPF on Cloudflare: one record, watch the lookup count
SPF has two Cloudflare-flavoured pitfalls beyond the universal "exactly one record" rule.
First, the editor will happily let you create two TXT records starting with v=spf1. Cloudflare does not deduplicate or warn you. Two SPF records is a permerror, and every receiver treats it as a hard failure. If you add a new sending platform, edit your existing SPF record to add the new include:, do not add a second SPF TXT. After editing, verify there is only one with the SPF checker.
Second, Cloudflare does not flatten SPF or count your lookups for you. SPF allows a maximum of ten DNS-resolving mechanisms (include, a, mx, ptr, exists, redirect). Stack up Google Workspace, a CRM, a help desk and a marketing tool and you quietly cross ten, producing a permerror and an SPF failure regardless of how correct each include is. Cloudflare gives you no signal that this has happened. The classic fix is flattening (resolving the includes to IPs so the record stays under the limit), which Cloudflare does not do natively. Read SPF PermError: too many DNS lookups and Fix SPF PermError, and our hosted SPF flattening keeps a single flat record under the limit and updates it as your senders change.
A note on syntax that Cloudflare itself is fine with but people still get wrong: use -all (hard fail) for a locked-down domain and ~all (soft fail) only while you are still discovering senders. Cloudflare stores either faithfully; the choice is yours and only matters at the receiver.
DMARC on Cloudflare: start at monitoring, then tighten
The DMARC record is a single TXT at _dmarc. Start in monitoring mode so you collect data before any mail is affected:
v=DMARC1; p=none; rua=mailto:dmarc-rua@example.com; fo=1; adkim=s; aspf=s
A few Cloudflare-specific and DMARC-specific details:
- Put a real, monitored mailbox in
rua. Aggregate reports (RUA) are XML, sent daily, and are how you learn which sources send as your domain before you enforce. Cloudflare does not parse them for you. Pipe them into the DMARC report analyzer or use our emailed monitoring so the XML becomes a readable picture. - External RUA destinations need authorisation. If your
ruamailbox is on a different domain from the one being protected, that other domain must publish a_report._dmarcauthorisation record. If you keep RUA on the same domain, you skip this. It is a DMARC rule, not a Cloudflare one, but Cloudflare will not warn you either way. - Move through the policy stages deliberately.
p=nonetop=quarantinetop=reject, usingpctand subdomain policy (sp) as controls. The reasoning and pacing are in DMARC policy: none vs quarantine vs reject, and the alignment tagsadkim/aspfare explained alongside the common errors in Common DMARC mistakes.
Do not jump to p=reject on day one. The whole point of starting at none on Cloudflare or anywhere else is to see your real sending sources in the reports first, fix any that fail alignment, then enforce.
Cloudflare Email Routing and authentication
Many Cloudflare users turn on Email Routing to forward you@example.com to a personal inbox. When you enable it, Cloudflare automatically adds MX records and an SPF record to your zone. Two things to know:
- It can overwrite or conflict with your existing SPF. If you already had
v=spf1 ...at the root, enabling Email Routing may add another, and now you have two SPF records, which is apermerror. After enabling Email Routing, check the root TXT records and merge into a single SPF that includes both your sending platforms and Cloudflare'sincludeif required. Verify with the SPF checker. - Email Routing handles inbound forwarding, not your outbound authentication. It does not sign your outbound mail with DKIM or set up DMARC for you. You still publish DKIM for whatever platform sends your mail, and you still publish the DMARC record yourself. Forwarding also has its own alignment quirks because forwarded mail can break SPF; that interaction is covered in Forwarding and DMARC and DKIM, alignment and forwarding.
Editing safely: Cloudflare keeps no per-record history you can roll back
When you click into an existing record and change it, Cloudflare overwrites it immediately on save. There is no built-in per-record undo, and the audit log shows that a change happened but does not give you a one-click revert of the old value. Practical habits:
- Copy the current value into a note before editing, especially for SPF and DKIM, so you can restore it if the change misbehaves.
- Use the bulk export. Under DNS then Records there is an Export option that downloads your zone file. Take an export before a round of authentication changes; it is your rollback.
- Change one record at a time and verify before moving on. Add or edit DKIM, confirm it with the DKIM checker; edit SPF, confirm with the SPF checker; then touch DMARC. Batching all three and discovering a failure leaves you guessing which one broke.
Doing it at scale: the Cloudflare API and Terraform
If you manage many zones, the dashboard is not the only way. Cloudflare exposes the same DNS operations over its API and Terraform provider, which matters for authentication records because they are easy to template and audit.
- API. A
POSTto the zone'sdns_recordsendpoint with a JSON body specifyingtype,name,contentandproxied: falsecreates a record. For DKIM CNAMEs,proxied: falseis the field that maps to "DNS only" (grey cloud); never set it totruefor authentication records. - Terraform. The
cloudflare_record(orcloudflare_dns_recordin newer provider versions) resource lets you declare SPF, DMARC and DKIM as code, withproxied = falsefor the CNAME. This is the cleanest way to keep dozens of domains consistent and to code-review changes to authentication.
Whichever route you use, the underlying rules from this guide do not change: one SPF TXT at the root, one DMARC TXT at _dmarc, DKIM per selector, no proxy on the CNAMEs, and the long DKIM key pasted as a single string for Cloudflare to chunk.
A quick end-to-end checklist
Run through this after publishing on Cloudflare:
- Zone is Active (full setup), not partial, and Cloudflare is authoritative.
- Exactly one SPF TXT at
@, under ten DNS lookups, ending in-allor~allas intended. - One DMARC TXT at
_dmarc, starting atp=none, with a realruamailbox you actually read. - DKIM published per sending platform, CNAMEs set to DNS only (grey), TXT keys pasted as one line.
- TTL on Auto, lowered to 1 minute only ahead of a planned rotation.
- Email Routing, if enabled, has not left you with a duplicate SPF record.
- Everything verified by lookup, not by the editor's "saved" message: DMARC checker, SPF checker, DKIM checker, and DNS propagation checker.
The takeaway
Cloudflare removes most of the painful mechanics: it chunks long DKIM keys, it handles apex CNAME flattening, and TTL is one click on Auto. What it does not do is think about email authentication for you. It will let you publish two SPF records, proxy a DKIM CNAME into oblivion, paste half a DKIM key, or sail past the ten-lookup SPF limit, all without a warning. The discipline that makes Cloudflare safe is the same on every host: right type, right name (prefix only), one SPF, DNS-only CNAMEs, monitor first with p=none, and verify by lookup rather than trusting the dashboard.
When you are ready to move from "the records exist" to "the records are correct and enforced", the staged path to p=reject is the real work, and it is exactly what we automate. See hosted DMARC, hosted SPF and hosted DKIM for the done-for-you route, or start free by pointing the DMARC checker at your domain and turning on emailed monitoring so any future change to these Cloudflare records pages you the moment it happens.