Skip to main content

Compare

The Cloudflare Email alternative on any DNS

Send over REST or SMTP from a platform that posts signed webhooks straight to your endpoint. Your domain keeps the DNS provider it already has.

What arrives assembled

Cloudflare Email Service sells the send. Everything around it is yours to build.

What comes with the plan on mailkube, and what you assemble yourself on Cloudflare Email
Comes withmailkubeCloudflare EmailDocs
WebhooksYesQueuesDocs(opens in a new tab)
Stored templates, versionedYesNoDocs(opens in a new tab)
Scheduled sending30 daysNoDocs(opens in a new tab)
Idempotency keysYesNoDocs(opens in a new tab)
Framework packagesDjango, Laravel, Rails, Spring BootNoDocs(opens in a new tab)

Four of those rows say No, and Cloudflare’s public documentation describes none of them. The webhook row is the sharpest. A delivery event there never reaches your endpoint. You create a queue, subscribe it to one sending domain, then write a Worker to read it. Forwarding that event to your own server is your code, and so is the signature on it.

One requirement sits before all of that. Email Service runs only on a domain whose DNS is already at Cloudflare. Their documentation describes no path for a domain hosted anywhere else.

A new account also sends against a daily quota Cloudflare never publishes. It rises with your sending behaviour, your deliverability and your account standing.

Feature by feature

The rows below hold what each platform documents today. A docs link opens the mailkube page behind that row.

Feature by feature, mailkube against Cloudflare Email
FeaturemailkubeCloudflare EmailDocs
Where account data is storedEuropean UnionNot documented
Free plan4,000 a month, 140 a dayNo
Dedicated IPsIncluded from EliteNot documentedDocs(opens in a new tab)
Per-topic opt-out on a sendYesNoDocs(opens in a new tab)
Outbound body and link scanYesNot documented
Webhook event types116Docs(opens in a new tab)
REST APIYesYesDocs(opens in a new tab)
SMTP relayYesYesDocs(opens in a new tab)
Official SDKsNode, Python, Go, Java, PHP, RubyNode, Python, GoDocs(opens in a new tab)
CLIYesYesDocs(opens in a new tab)

"Not documented" means the public Cloudflare Email documentation does not describe it. Checked on September 29, 2026.

Dedicated IPs are included from the Elite plan. Elite carries one at 100,000 emails a month, and Volume carries six at 750,000. Each new one warms on a six-stage ladder, from 50 messages a day to 10,000. Cloudflare manages reputation on shared addresses and documents no dedicated IP at all.

Email Sending is in public beta. The documentation index carries the badge and the pricing page carries none.

Where your data lives

Customer data is stored in the European Union. Our infrastructure runs in European data centres, in the French OVHcloud group.

Cloudflare’s Email Service documentation names no region for the messages it handles. Message preview is on for a new sending domain by default, and it keeps the message about seven days.

The detail is in the data processing agreement.

Two transports, headers included

POST to the REST API, or point the SMTP client you already run at smtp.mailkube.com. Everything the API takes as a JSON field, SMTP takes as a header. Those headers are stripped before the message reaches the recipient.

  • X-Mailkube-Tags carries the same tag list as the REST tags field
  • X-Mailkube-Topic attributes the send to a topic, so recipients who opted out are filtered
  • X-Mailkube-Template-Id and X-Mailkube-Template-Version render a saved template server-side

An SMTP send is the same message as an API send. It lands in the same logs, counts against the same quota and fires the same webhook events. The SMTP reference(opens in a new tab) lists every header, reply code and rate limit.

Cloudflare relays SMTP on smtp.mx.cloudflare.net, on port 465 under implicit TLS, with the literal string api_token as the username. Its send API takes a headers object, and any header starting with X- travels with the message. Its delivery analytics carry no dimension for those headers, so a tag set there filters nothing afterwards. Cloudflare’s own documentation adds that Email Service does not process unsubscribe links, and asks you to suppress those recipients yourself.

One more difference sits on the send itself. Every mailkube send takes an idempotency key(opens in a new tab) , and a retried call returns the first result instead of sending twice. The Cloudflare API documents no such key, and a retried call sends a second message.

Your stack, already covered

Official SDKs cover Node, Python, Go, Java, PHP and Ruby. Django, Laravel, Rails and Spring Boot each have a package of their own. It plugs into the framework’s mail layer, and every client verifies your webhook signatures for you.

Cloudflare publishes three client libraries, for Node, Python and Go. Each one covers its whole platform rather than email alone. It publishes no framework package, so a Django or Laravel project wires the transport itself.

The CLI is a single binary. It sends over either transport and manages scheduled sends. While you develop, it runs a local webhook receiver. It carries a skill file, and a coding assistant reads the real command surface. Start from the SDK documentation(opens in a new tab) or the CLI guide(opens in a new tab) .

Migrating from Cloudflare Email

The Node SDK runs on Workers with no compatibility flag to set. Keep the Worker, swap the client, and read the key from the same env binding.

The same send, Cloudflare Email on the left and mailkube on the right

Cloudflare Email

export default {
  async fetch(request, env) {
    await env.EMAIL.send({
      from: { email: "you@example.com", name: "Your app" },
      to: [{ email: "customer@example.com" }],
      subject: "Hello world",
      text: "It works!",
      html: "<p>It works!</p>",
    });

    return new Response("sent");
  },
};
Host
smtp.mx.cloudflare.net
Port
465

mailkube

import { Mailkube } from "@mailkube/mailkube-node";

export default {
  async fetch(request, env) {
    const mailkube = new Mailkube(env.MAILKUBE_API_KEY);

    await mailkube.emails.send({
      from: "you@example.com",
      to: "customer@example.com",
      subject: "Hello world",
      html: "<p>It works!</p>",
    });

    return new Response("sent");
  },
};
Host
smtp.mailkube.com
Port
587

SMTP takes one change more than the usual two. Move the host and the credential, then move the port from 465 to 587, where your mailer negotiates TLS on a session it has already opened. The messages you already send go out unchanged, and tags, topics and templates arrive as headers when you want them. Nothing forces a cutover date: run both platforms side by side and move one service at a time. The quickstart(opens in a new tab) covers the REST path and the SMTP guide(opens in a new tab) covers the relay.

When Cloudflare Email is the better fit

Email Service lives inside Cloudflare’s developer platform. A Worker sends through a binding with no API key to manage. Wrangler drives it from the same configuration as the rest of a deployment, and one account and one bill cover everything. A team already building there inherits all of it.

Authentication is configured for you as well. Cloudflare writes the SPF, DKIM and DMARC records when you onboard a domain, and you add nothing by hand. Here you place those records at your own provider, wherever that is.

The pricing page details every plan. The REST API and SMTP relay pages go deeper on the two transports.

Frequently asked questions

Frequently asked questions

What does Cloudflare Email ask for that mailkube does not?
Your DNS. Email Service runs only on a domain whose DNS is already at Cloudflare, and their documentation describes no path for a domain hosted anywhere else. Here you verify a domain with records you place at your own provider.
How do delivery events reach my server?
On mailkube they arrive as an HTTP POST at the endpoint you registered, signed with an HMAC your SDK checks. Cloudflare publishes them only into one of its queues. You create the queue, subscribe it to a sending domain, and write a Worker to read it.
Is Cloudflare Email Sending finished?
It is in public beta. The documentation index carries the badge, the pricing page carries none, and the published support route is a community forum. Cloudflare added its delivery events three months after the beta opened.
Can I keep my SMTP configuration?
Yes, with one change more than usual. Point your mailer at smtp.mailkube.com on port 587 rather than 465, with a credential bound to your verified domain. Tags, topics and templates then travel as X-Mailkube headers on the message you already send.
Can I schedule a send?
Yes, on every paid plan, up to 30 days ahead, and the CLI manages the queue. The Cloudflare send API takes no scheduling parameter on any of its three transports.
Where do the Cloudflare figures come from?
From the public documentation and pricing pages on cloudflare.com. The date under the feature table is the day they were last read. A change on their side moves that date.

Send your first email today

Start free, no card. Point an existing SMTP client at us, or install an SDK and make one POST.