# Verify a sending domain with Cloudflare DNS

Send as your own domain: add the domain in SendBeam, put its CNAME records in your Cloudflare zone, and confirm the mail is signed and aligned.

Mail that claims to come from your domain has to prove it, and the proof lives in your DNS: a
signature the receiving server can check against a key published in your zone, and a bounce
address on your domain so failures come back to the right place. Since 2024, Gmail, Yahoo and Microsoft
have enforced this for bulk senders rather than merely preferring it, so a campaign from an
unauthenticated domain is refused at the door rather than filtered into spam. This guide takes a
domain whose DNS is on Cloudflare from nothing to verified, and shows
how to prove afterwards that it worked.

## Why the records are needed

SendBeam delivers your mail through its own managed infrastructure. That infrastructure can sign
as `yourbrand.com` only if `yourbrand.com` publishes something that says so.
The records do two jobs. The **signing records** publish the public half of the key
your mail is signed with, so a receiving server can verify the signature and see
`dkim=pass` for your domain. The **return-path record** gives your mail a
bounce address on a subdomain of your own domain, which aligns the envelope sender with the From
header and lets SendBeam collect bounces and complaints and suppress dead addresses for you.

Everything you add is a **CNAME** pointing at a name under
`dom.sendbeam.io`. SendBeam hosts the real values, so your zone never names a third
party and those values can be rotated without you touching DNS again.

## Prerequisites

- A SendBeam workspace, and the **admin** role in it — sender details and sending domains are admin-only.
- A domain you control, either an apex (`yourbrand.com`) or a subdomain (`news.yourbrand.com`). Your plan sets how many sending domains your account may have.
- Cloudflare as the DNS host: the zone exists in your account and the domain's nameservers point at it. If DNS lives elsewhere, make the changes there instead.

## Steps

1. **Add the domain in SendBeam.** Open **Settings > Email & Domains**
  (`/settings/domains`), and under *Add your domain* type the domain and press
  **Add Domain**. SendBeam registers it with its managed delivery and lists
  the records in a table with a live *found / not found* column, under the status
  **Add DNS records**.
2. **Read what you have been given.** Every row is a CNAME: the name is a label on
  your domain, the value the matching name under `dom.sendbeam.io`, derived from a
  stable hash of your domain so it never changes. There is nothing to add at the apex, no TXT
  record to merge and no MX record to touch.
3. **If you see "Connect with Cloudflare", press it.** This is Domain Connect, the
  open standard Cloudflare, GoDaddy, IONOS and others implement: you land on Cloudflare — signed
  in already, or after its own login — looking at the CNAME records with SendBeam's name on
  them. Approve, and Cloudflare adds them and sends you back; SendBeam re-checks straight away.
  SendBeam never sees a password or an API token, and the request is signed so Cloudflare knows
  it came from SendBeam. The button appears only once a provider has enabled SendBeam's template
  on its side, so if it is not there, add the records yourself — the step below is the same two
  records and takes a minute.
4. **Add them yourself.** In the Cloudflare dashboard open the zone, go to
  **DNS > Records > Add record**, choose type **CNAME**, copy the
  name and the value from SendBeam's table, set **Proxy status** to
  *DNS only*, leave TTL on Auto, and save. Repeat for each row.
  TypeName (on your domain)Value (target) CNAME`._domainkey.yourbrand.com``._domainkey..dom.sendbeam.io` CNAME`.yourbrand.com``..dom.sendbeam.io`
  Those are shapes, not values — copy the exact names from the page.
5. **Wait for verification.** A scheduler re-checks unverified domains every minute
  (at most once every five minutes per domain), so you need not sit on the page; the
  **Verify** button forces a check now. **Add DNS records** means at
  least one CNAME is still missing. **Verifying** means they all resolve and the
  delivery side is finishing its own check, which takes a few minutes and needs nothing from you.
  **Verified** means you can send, and **Failed** that the delivery side
  rejected the domain. Re-checks stop after 30 days unverified.
6. **Choose the address you send from.** On a verified domain the card offers a
  local part — `hello`, `news` — and a **Set as default**
  button. The from-name lives in *Sender details* at the top of the same page, and replies
  go to the from-address.

> **The proxy must be off.** An orange-cloud CNAME resolves to Cloudflare's own
> addresses, not the target you typed, so the record is invisible to mail verification even though
> it looks right in the dashboard. Hiding the target is the point of the proxy for web records;
> for mail records it is simply wrong. Grey cloud, always.
> 

What the connect path does *not* do is worth stating plainly. It creates only the CNAMEs
SendBeam listed — no DMARC, no SPF, no MX — and Cloudflare shows you exactly those before anything
is written. It never edits or deletes a record you already have. If you decline at Cloudflare,
nothing changes and the card says so; the manual route below is always there.

## Add a DMARC record

DMARC is not part of verification and SendBeam will not add it for you, but it turns passing
signatures into a policy: it tells receivers what to do with mail that claims to be you and
fails, and it is where reports about mail sent in your name come from. If
`_dmarc.yourbrand.com` does not exist yet, add it in Cloudflare as a TXT record:

```
Type:  TXT
Name:  _dmarc            (that is _dmarc.yourbrand.com)
Value: v=DMARC1; p=none; rua=mailto:dmarc@yourbrand.com; fo=1
```

Start at `p=none`. It changes nothing about how your mail is treated, which is the
point: for a week or two the reports at the `rua` address tell you what else sends as
your domain — a helpdesk, an invoicing tool, a form on an old site — before a policy can bounce
any of it. Then move to `p=quarantine` and on to `p=reject`, as
[Getting started > Sending domain](https://sendbeam.io/docs/getting-started/sending-domain) recommends.
A strict policy on a domain you have never measured is how legitimate mail disappears quietly.

## Verify it worked

1. The domain shows **Verified** in **Settings > Email & Domains**, with the date, and your from-address is set on it.
2. Press **Send test email** in *Sender details*. It sends to your own login address from the address you configured.
3. Open the message's original or full headers. You are looking for a pass on your own domain, not on a shared one:
  `Authentication-Results: mx.example.com;
  dkim=pass header.d=yourbrand.com;
  spf=pass smtp.mailfrom=.yourbrand.com;
  dmarc=pass header.from=yourbrand.com`
4. For a second opinion, run the domain through [the sender check tool](https://sendbeam.io/tools/sender-check), which grades your public records as a receiver sees them.
5. If a record looks wrong, check it at the source, not in the dashboard:
  `# Is the record live, and does it point where SendBeam expects?
  dig +short CNAME .yourbrand.com
  # → ..dom.sendbeam.io.
  
  # A proxied record answers with addresses instead of the target — that is the bug:
  dig +short .yourbrand.com
  # → 104.21.x.x (grey-cloud the record)`

## Troubleshooting

**The record ended up at the wrong name.** Cloudflare's Name field is relative to
the zone, and pasting a full name into a panel that appends the zone gives you
`send.yourbrand.com.yourbrand.com`. After saving, read the name Cloudflare shows in the
record list — not what you typed — and confirm it matches SendBeam's table. It bites hardest when
the sending domain is itself a subdomain: for `news.yourbrand.com` in the
`yourbrand.com` zone, the record name carries the `news` label too.

**You already have an SPF record.** SendBeam does not ask you to change it: the
return path sits on a subdomain of your domain, so alignment is handled there and nothing is
needed at the apex. Leave any `v=spf1 …` record you have for other senders alone — a
domain may publish only one SPF record, and a second makes both invalid. If you ever do need
another sender's include, merge it into the existing record; never add a second.

**The record is proxied.** See the warning above. Set Proxy status to
*DNS only*, and note that switching an existing record to grey cloud counts as a change
that has to propagate.

**Nothing has propagated yet.** Cloudflare publishes edits within seconds, but the
resolver SendBeam queries can hold an earlier negative answer for the length of the old TTL.
If the table still says *not found* after ten minutes and `dig` on your own
machine sees the record, press **Verify** once more before assuming a mistake.

**"That domain is already registered."** A sending domain belongs to one workspace
across all of SendBeam. If it is set up in another workspace of yours, remove it there first or
use a different subdomain here. Domains also match exactly: verifying `yourbrand.com`
does not let a workspace send as `news.yourbrand.com`, and that check runs when you
save the from-address and again on every send.

**The status went to Failed.** The delivery side rejected the domain rather than a
DNS lookup failing. Check the names once more, then remove the domain and add it again for a
fresh set of records; if it fails again, [get in touch](https://sendbeam.io/contact) — that one is not
fixable from your zone.

## Next steps

- [Getting started > Sending domain](https://sendbeam.io/docs/getting-started/sending-domain) for the shared platform addresses, plan pools and from-address rules.
- [Contacts > CSV import](https://sendbeam.io/docs/contacts/importing) to bring your audience in now that mail leaves as your own domain.
- [Moving in from another platform](https://sendbeam.io/move-in) if the domain is already verified somewhere else and you are switching over.

## Starter kits

Once the domain is verified, these starters send from it with no change beyond the form IDs.
Each is a small site you can deploy and point at your workspace:

- Astro [Astro on Cloudflare Pages No API key needed · Cloudflare Pages Signup and contact components, form IDs in PUBLIC_ environment variables, and a _headers file that lets Turnstile load. sendbeam-starters/astro-cloudflare-pages](https://github.com/sendbeam-io/sendbeam-starters/tree/main/astro-cloudflare-pages)
- HTML and vanilla JS [Plain HTML No API key needed · Any static host One page, one script, no build step: paste the files onto any host and both forms work. sendbeam-starters/plain-html](https://github.com/sendbeam-io/sendbeam-starters/tree/main/plain-html)
- Hugo [Hugo No API key needed · Any static host Two partials and one script in static/, with the form IDs read from site params in hugo.toml. sendbeam-starters/hugo](https://github.com/sendbeam-io/sendbeam-starters/tree/main/hugo)
- Eleventy [Eleventy on Netlify No API key needed · Netlify Nunjucks includes and a global data file, with a netlify.toml that sets the Content-Security-Policy for you. sendbeam-starters/eleventy-netlify](https://github.com/sendbeam-io/sendbeam-starters/tree/main/eleventy-netlify)
- Next.js (App Router) [Next.js on Vercel No API key needed · Vercel Client components that post straight to the form endpoint, so no route handler and no secret sit in the middle. sendbeam-starters/nextjs-vercel](https://github.com/sendbeam-io/sendbeam-starters/tree/main/nextjs-vercel)

Every starter covers the same five things — newsletter signup, contact form, double opt-in,
unsubscribe and spam protection — reads its form IDs from environment variables or site config,
and is MIT licensed. Browse them all in
[sendbeam-starters](https://github.com/sendbeam-io/sendbeam-starters).

---
Source: https://sendbeam.io/docs/guides/sending-domain-cloudflare-dns
