Skip to content
Go back

Email Without Third Parties: Sending Mail Straight From a Cloudflare Worker

Every app I’ve ever built eventually needed to send an email. A welcome message. A receipt. A password reset. A notification from an agent.

And every single time, that meant reaching for a third party: SendGrid, Mailgun, Amazon SES, Postmark. Sign up, verify a domain, generate an API key, paste it into a secrets store, install an SDK, wire up a client. Then spend an afternoon fighting SPF and DKIM records until your test emails stop landing in spam.

Cloudflare’s Email Service deletes that entire checklist. I added live, authenticated email sending to saltwaterbrc.com with one binding and one line of code — no API key, no SDK, no third party. And because Cloudflare already runs my DNS, it configured SPF, DKIM, and DMARC for me automatically.

Here’s exactly how it works — and there’s a live demo at the bottom you can try with your own inbox.


The whole integration: one binding, one line

In a normal stack, “send an email from your backend” is a project. On Workers, it’s a binding.

Here’s the entire Wrangler config change:

{
  "send_email": [{ "name": "EMAIL" }]
}

And here’s the entire send:

const { messageId } = await env.EMAIL.send({
  to: "you@example.com",
  from: "demo@send.saltwaterbrc.com",
  subject: "👋 Sent live by Cloudflare Email Service",
  html: "<h1>Hello from the edge</h1>",
  text: "Hello from the edge",
});

That’s it. No Authorization header. No secret to rotate. No npm install. The EMAIL binding is the credential — scoped, managed, and invisible. The Worker calls send() and Cloudflare’s network handles delivery.

When I first ran it, I genuinely double-checked that I hadn’t forgotten a step. I hadn’t.

The part that normally ruins your week: authentication

If you’ve ever set up transactional email, you know the real pain isn’t the API call — it’s deliverability. Get SPF, DKIM, or DMARC wrong and your mail silently rots in spam folders. These are fiddly DNS records that every provider documents slightly differently, and you usually only find out you got them wrong when a customer says “I never got the email.”

Because Cloudflare already manages my DNS, onboarding a sending domain added all three automatically. I picked a subdomain — send.saltwaterbrc.com — clicked through, and watched these appear in my DNS table without typing a single record:

That last one is worth a pause. I set the sending subdomain to p=reject — the most aggressive DMARC policy — without hesitation, because only Cloudflare sends from send.saltwaterbrc.com. Nothing legitimate will ever fail, so there’s no reason to be lenient. My main domain stays on a cautious p=none (it carries real Google Workspace mail), but the dedicated sending subdomain is locked down hard. Separating the two is the whole trick.

Why a subdomain, not the main domain

This is the detail that makes the whole thing safe to ship. My primary email — brandon@saltwaterbrc.com — runs on Google Workspace, with an MX record pointing at Google’s servers. Outbound sending lives entirely on the send. subdomain and never touches that MX record.

The payoff is reputation isolation. If this public demo ever gets abused, it’s send.saltwaterbrc.com that takes the deliverability hit — not my real domain. My actual inbox keeps working no matter what happens to the demo. Transactional and human email should never share a sending reputation, and a subdomain gives you that separation for free.

The agent angle

There’s a reason Email Service launched during Agents Week. AI agents running on Workers increasingly need to act — and “send the user an email” is one of the most common actions there is. A research agent emails you the report. A monitoring agent emails you the alert. A booking agent emails you the confirmation.

Before, that meant wiring an external email provider into your agent’s tool list, with all the key management that implies. Now it’s just another Worker binding the agent can call. The agent sends email as natively as it reads from a database or queries a vector index. No third party in the loop, nothing to leak, nothing to rotate.

The demo: prove it with your own inbox

Talk is cheap, so I built a live one. On the Email Service demo page, you enter your email address, and a Worker sends you a real message — right now, from the edge.

The email you receive isn’t a generic “hello.” It’s a delivery trace of the exact message you’re reading: the timestamp, the Cloudflare data center that processed your request, your connection’s HTTP and TLS versions, the sending address, and a note on how it was authenticated. Everything in it is genuinely captured at send time.

What it deliberately doesn’t do is claim “DKIM: pass ✓” in the body — because that verdict is computed by your mail provider after delivery, not by the sender. So instead, the email points you to your client’s “Show original” view, where you can see the real DKIM signature and the SPF/DMARC pass results your provider computed. Don’t take my word for it; read the headers.

Built to send safely, with the rest of the platform

A public “email anyone” endpoint is also a public spam cannon if you build it naively. So the demo is wrapped in three other Cloudflare products, each doing one job:

That’s four products — Email Service, Turnstile, Rate Limiting, and Workers — collaborating behind a single button. Which is really the whole point of building on one connected platform: the pieces are designed to snap together.

What got deleted

The best features are the ones that remove work. Adding email to this site didn’t add a vendor, a dashboard, a monthly bill, an API key, or a deliverability project. It added one binding and one line.

That’s product number 35 running in production on saltwaterbrc.com — and the first one whose main selling point is everything it let me not do.

Try the live demo →


Share this post on:

Next Post
Where Does Your Data Live? Proving It With Cloudflare Regional Services