Skip to content
Groundmail

Guides

How to add SPF, DKIM and DMARC records in Cloudflare

Add SPF, DKIM, DMARC, MX and mail CNAME records in Cloudflare, why return-path and tracking CNAMEs must be DNS only, and Email Routing's locked SPF.

By GroundmailUpdated All guides →

Short answer

In the Cloudflare dashboard, select your domain, go to DNS > Records and select Add record. SPF, DKIM and DMARC are all TXT records: enter @ (the root), selector._domainkey or _dmarc in Name, paste the value into Content and select Save. You don't need quotation marks; Cloudflare adds them when you save.

The Cloudflare-specific trap is the proxy. Any CNAME an email service asks for, such as a return path, link tracking or a DKIM CNAME, must be set to DNS only (grey cloud), not Proxied (orange cloud). A proxied record answers with Cloudflare's own IP addresses instead of the target, so the email service's check fails. TXT and MX records are always DNS only.

Before you start: is Cloudflare answering for the domain?

Records you add in Cloudflare only count if the domain's nameservers are Cloudflare's. If you registered the domain elsewhere and moved its nameservers to Cloudflare, add records in Cloudflare, not at the registrar. Check from a terminal:

Terminal
dig +short NS example.com

# Cloudflare's nameservers end in ns.cloudflare.com, for example:
# ada.ns.cloudflare.com.
# bob.ns.cloudflare.com.

Also check whether Email Routing is on for the domain. If it is, Cloudflare has already added MX records, an SPF record and a DKIM record for it, and it locks them so they can't be edited by accident. That matters for SPF and MX below.

Add a TXT record (SPF, DKIM or DMARC) in Cloudflare

Step 1: Open DNS records

In the Cloudflare dashboard, select your account and domain, then go to DNS > Records. Search the list for an existing TXT record starting v=spf1 and a record named _dmarc first: if either exists, you'll edit it instead of adding another.

Cloudflare DNS > Records page, searched for _dmarc to check for an existing DMARC record, with the Add record button

Step 2: Select Add record and choose TXT

Select Add record and choose TXT as the Type. There's no separate SPF type; SPF is a TXT record whose content starts with v=spf1.

Cloudflare's Add record form with the Type menu open and TXT highlighted

Step 3: Enter the Name

Use @ for the root domain. For other records, enter the name without your domain, as Cloudflare's own examples do (_dmarc, google._domainkey). After you save, the record list shows the full name; check that it reads _dmarc.example.com and not the domain twice.

Step 4: Paste the Content

Paste the value into Content as one line. You can leave quotation marks out: for a new record saved without quotes, Cloudflare adds the double quotes itself. Don't paste a value with stray quotes in it (an opening quote with no closing one, or quotes in the middle); Cloudflare rejects inconsistent quotation marks. Leave TTL on Auto.

Cloudflare Add record form for a TXT record: Name _groundmail, Content groundmail-verify=…, TTL Auto

Step 5: Save

Select Save. There's no proxy option on TXT records, so there's nothing else to set. If you changed an existing record, resolvers that cached the old answer keep it until its TTL runs out, so give it a few minutes before you check.

Add a CNAME for email: DNS only, not proxied

Email services use CNAMEs for the return path (bounce) domain, for link and open tracking, and sometimes for DKIM. Cloudflare can proxy A, AAAA and CNAME records, and a proxied record no longer answers with your CNAME target; it answers with Cloudflare's anycast IP addresses. The email service looks for its own host name, doesn't find it, and the check fails. Cloudflare's own guidance is that DNS records used for email should be DNS only.

Step 1: Select Add record and choose CNAME

On DNS > Records, select Add record and choose CNAME as the Type.

Step 2: Enter the Name and Target

Enter the prefix your email service gives you in Name (for example rp, ps or s1._domainkey) and its host name in Target.

Cloudflare Add record form for a CNAME rp pointing to rp.groundmail.dev, with Proxy status on (Proxied, orange cloud), which is the default

Step 3: Switch Proxy status to DNS only

Look at Proxy status before you save. A new CNAME starts out Proxied, with an orange cloud, so switch it off until it reads DNS only with a grey cloud. Do this on every mail CNAME.

The same CNAME with Proxy status switched off: DNS only, grey cloud

Step 4: Make sure the record isn't flattened

CNAME flattening has the same effect as the proxy: Cloudflare answers with IP addresses instead of the CNAME. If the record shows a Flatten setting, leave it off, and if the zone's DNS settings have CNAME flattening for all CNAME records turned on, turn it off or the email service still won't see its target.

Step 5: Save, and fix any existing proxied mail CNAMEs

Select Save. Then scan the list for mail CNAMEs added earlier with an orange cloud: edit each one, switch it to DNS only and save.

Add an MX record in Cloudflare

Select Add record, choose MX, enter the Name (@, or a subdomain such as inbound), the Mail server host name and the Priority (lowest is tried first), then Save. MX records are always DNS only. The host name an MX record points to must also resolve without the proxy: if it's a name in your own zone, such as mail.example.com, that record has to be DNS only too.

If Email Routing is on, its MX records on the root are locked, and they can't coexist with another provider's MX records on the same name. Either put the new service's MX records on a subdomain, or turn Email Routing off for the domain before you change the root's MX records.

What to enter for each email record

RecordTypeNameContent or target (example)Proxy status
SPFTXT@v=spf1 include:_spf.example-provider.com ~allAlways DNS only
DKIM keyTXTselector._domainkeyv=DKIM1; k=rsa; p=MIIBIjANBgkq…Always DNS only
DKIM, delegatedCNAMEselector._domainkeyA host name from your providerDNS only
DMARCTXT_dmarcv=DMARC1; p=none; rua=mailto:dmarc@example.comAlways DNS only
Return pathCNAMEThe prefix your provider names, such as rpA host name from your providerDNS only
Link and open trackingCNAMEThe prefix your provider namesA host name from your providerDNS only
Receiving mailMX@ or a subdomainMail server host name, plus a priorityAlways DNS only

Names are for example.com. For a subdomain such as mail.example.com, keep the subdomain in the name: _dmarc.mail, selector._domainkey.mail, and mail instead of @.

Cloudflare SPF: one record, and Email Routing's lock

A name can have only one SPF record; with two, SPF fails for every message. If Email Routing is on, the root already has v=spf1 include:_spf.mx.cloudflare.net ~all, and Cloudflare locks it. To add a sending service, open Email Routing for the domain, go to its Settings, find the SPF record under DNS records and select Unlock. Then edit the record in DNS > Records so it holds both includes:

One merged SPF record (TXT at @)
v=spf1 include:_spf.mx.cloudflare.net include:_spf.example-provider.com ~all

SPF is limited to 10 DNS lookups, including the ones nested inside each include. The SPF checker counts them.

Cloudflare DKIM: long keys are split for you

Paste a DKIM key into Content as one line, without quotes and without splitting it. A 2048-bit key is about 400 characters, longer than the 255 a single DNS text string can hold, so Cloudflare stores it as two or more strings. That's why the saved record can show a double quote in the middle of the key: it's expected, and receivers join the strings back together. Email Routing's own DKIM key uses the selector cf2024-1, so it sits alongside your sending service's key without clashing.

Cloudflare DMARC: one record, and DMARC Management

Add one TXT record named _dmarc, starting at p=none with a rua= address so you get reports, and tighten it to quarantine and reject once the reports show your mail passing. If a _dmarc record exists, edit it; two DMARC records make receivers ignore both.

Cloudflare's DMARC Management (under Email > DMARC Management) collects those reports for you. When you turn it on, Cloudflare adds its own report address to the rua= tag of your existing record, so if you edit the record later, keep that address or the reports stop. It works for apex domains such as example.com, not for a subdomain set up as its own zone.

Check that the records work

Terminal
# SPF: expect exactly one line starting "v=spf1"
dig +short TXT example.com @1.1.1.1

# DKIM: a long key comes back as several quoted strings, which is normal
dig +short TXT s1._domainkey.example.com @1.1.1.1

# DMARC: expect exactly one "v=DMARC1" line
dig +short TXT _dmarc.example.com @1.1.1.1

# Return path: expect your provider's host name, not an IP address
dig +short CNAME rp.example.com @1.1.1.1

# If the CNAME query is empty but this returns IPs, the record is proxied or flattened
dig +short rp.example.com @1.1.1.1

# MX
dig +short MX example.com @1.1.1.1

Common mistakes in Cloudflare DNS

MistakeWhat happensFix
Mail CNAME left Proxied (orange cloud)Resolves to Cloudflare IPs; the provider can't verify the return path or tracking domainEdit the record and set DNS only
CNAME flattening on for the record or the zoneSame as proxied: IP addresses instead of the CNAMETurn Flatten off for the record and zone-wide flattening off
A second SPF record next to Email Routing'sSPF permerror for every messageUnlock Email Routing's SPF record and merge both includes into it
New MX records on the root while Email Routing is onThey conflict with Email Routing's locked MX recordsUse a subdomain for the new service, or turn Email Routing off first
Stray or unbalanced quotes in TXT contentCloudflare rejects the record, or the value is wrongPaste the value with no quotes and let Cloudflare add them
Editing _dmarc and dropping Cloudflare's rua addressDMARC Management stops receiving reportsKeep the Cloudflare address in rua= alongside yours
Records added at the registrar instead of CloudflareNothing changes in public DNSAdd them in Cloudflare, which answers for the domain

Using Groundmail? Your records in Cloudflare

When you add a domain to Groundmail, you get the records below, written here the way Cloudflare's Name field takes them for example.com. Both CNAMEs must be DNS only: the return path so bounces and SPF alignment work, and the tracking host so tracked links and the open pixel can be served over HTTPS from your domain.

PurposeTypeName in CloudflareValue (example)Proxy status
OwnershipTXT_groundmailgroundmail-verify=1a2b3c…Not applicable
DKIMTXTss-abc123._domainkeyv=DKIM1; k=rsa; p=MIIBIjANBgkq…Not applicable
Return pathCNAMErprp.groundmail.devDNS only
SPFTXT@v=spf1 include:spf.groundmail.dev ~all, merged into any SPF record you already haveNot applicable
DMARCTXT_dmarcv=DMARC1; p=none; to start, unless the domain already has a DMARC recordNot applicable
Open and click tracking (optional)CNAMEpstrack.groundmail.devDNS only
Receiving (optional)MX@, or the subdomain you receive onmx.groundmail.dev, priority 10Not applicable

For a domain added as example.com. The token, the DKIM selector and the key are unique to your domain, so copy the real values from your dashboard. Ownership, DKIM, return path and SPF are needed to verify; DMARC is recommended. The tracking record appears only when open or click tracking is on, and the MX record only when receiving is on.

The dashboard shows full host names, such as _groundmail.example.com. Your DNS host adds the domain itself, so type only the part before it. If you added a subdomain such as mail.example.com, keep the subdomain in the name: _groundmail.mail, ss-abc123._domainkey.mail, rp.mail, mail for SPF and _dmarc.mail.

The quickest way on Cloudflare is to let Groundmail write them: save a Cloudflare API token under Integrations and select Apply DNS (Cloudflare), which adds every record as DNS only and merges SPF into the record you already have. To add them by hand instead, copy the real values from any of these:

  • Dashboard: open Domains, select the domain, then the DNS records tab. Each record has a copy button, and selecting a row shows the full host and value.
  • CLI: groundmail domains get example.com prints the domain with its records (install with npm install -g groundmail-cli).
  • API: GET /domains/{id} returns the same records list. See the domains docs.

Then select Verify DNS on the domain's page. Home reads your public DNS and names any record it can't find yet, and the DNS records tab marks each record and keeps re-checking while the domain is pending, so you can see which one is missing instead of waiting and guessing. Verifying also switches signing to your own domain, so messages carry a DKIM signature for example.com and DMARC can pass.

New to Groundmail? It sends your app's sign-in codes, password resets and receipts, and the free plan includes 3,000 emails a month with no time limit. Create a free account, add your domain, and the records above are generated for you.

Frequently asked questions

Should email DNS records be proxied in Cloudflare?

No. TXT and MX records can't be proxied at all, and every CNAME an email service gives you (return path, tracking, DKIM) should be DNS only. A proxied CNAME answers with Cloudflare IP addresses instead of the target, which breaks the service's checks.

How do I add a DMARC record in Cloudflare?

Go to DNS > Records, select Add record, choose TXT, enter _dmarc as the Name and a value such as v=DMARC1; p=none; rua=mailto:dmarc@example.com as the Content, then Save. Edit the existing _dmarc record instead if there is one.

How do I add a DKIM record in Cloudflare?

Add a TXT record named selector._domainkey with your provider's key as the Content, or a CNAME set to DNS only if your provider gives you a target. Paste the key as one line; Cloudflare splits long keys into several strings for you.

Why does my DKIM record show a quote in the middle in Cloudflare?

A DNS text string holds at most 255 characters, so a longer value is stored as several strings. Cloudflare's docs call this expected, and receivers join the strings back together before checking the key.

I use Cloudflare Email Routing. How do I add another service to SPF?

Unlock the SPF record in Email Routing's settings, then edit it in DNS > Records so it includes both: v=spf1 include:_spf.mx.cloudflare.net include:your-provider ~all. Don't add a second SPF record.

Do I need quotation marks around TXT values in Cloudflare?

No. If you save a new TXT record without quotes, Cloudflare adds them. Avoid partial or stray quotes, which Cloudflare rejects.

Sources

Facts on this page about other companies' products, prices and policies come from these public pages. They change, so check them before you decide.

Email for apps. Set up by your agent.

Sign-in codes, receipts and alerts kept separate from marketing mail, with inbound, templates and automations included. Start free with 3,000 emails a month, and move to a dedicated IP or server without changing your code.