Skip to content
USE CASES

Seven jobs. One API.

Each of these is code you’d otherwise spread across Resend, a marketing tool and a cron job. Here they are one deploy, on your own Workers. Pick the one you came for.

01 · TIME-CRITICAL

Login codes and password resets

The email that has to arrive in seconds or your support queue fills up. Send from the Worker that’s already handling the request — no cross-cloud hop, no cold start, median 41ms to accept.

  • Idempotency keys so a double-click can’t send twice
  • Separate stream and tag, so a newsletter bounce can’t hurt it
  • Time-to-accept per provider, plus seed-based placement — not just “delivered”
env.MAIL.send()
export default {
  async fetch(req, env) {
    const code = crypto.randomUUID().slice(0, 6);
    await env.MAIL.send({
      from: 'Acme <[email protected]>',
      to: email,
      subject: `${code} is your code`,
      template_id: 'tpl_login',
      data: { code },
      tags: [{ name: 'stream', value: 'auth' }],
    }, { idempotencyKey: `otp-${sessionId}` });
    return Response.json({ ok: true });
  },
};
POST /v1/emails
// Stripe webhook -> receipt with the PDF attached
await ms.emails.send({
  from: '[email protected]',
  to: invoice.customer_email,
  subject: `Receipt ${invoice.number}`,
  react: <Receipt invoice={invoice} />,
  attachments: [{ filename: 'invoice.pdf',
                  path: invoice.pdf_url }],
  tags: [{ name: 'stream', value: 'billing' }],
});
02 · MUST BE KEPT

Receipts, invoices and statements

Financial mail you may need to produce years later. Attachments and raw MIME live in your own R2 bucket, so retention is a lifecycle rule you write — not a plan tier someone sells you.

  • Keep seven years of copies at $0.015/GB, no egress fees
  • Batch up to 100 statements per call, queued and throttled
  • Exact payload of any historical send, replayable

Attachment ceilings are per transport: Cloudflare Email Service caps a message at 5 MiB (25 MiB only to verified destinations), Amazon SES accepts 40 MB. Attachment docs →

03 · HIGH VOLUME

Product notifications & digests

Mentions, comments, alerts, weekly summaries. The volume that makes per-email pricing hurt, and the category where bundling saves both money and inboxes.

Digest windows in a Durable Object

Collapse 40 “new comment” emails into one 9am digest per user with an alarm — instead of 40 sends and one unsubscribe.

Per-user preferences

Categories with their own opt-outs, honoured automatically at send time and in the hosted preference centre.

Cost at scale

A million notifications is ≈$363 on Cloudflare, or ≈$115 routed via SES. The math →

04 · RUNS IN YOUR ACCOUNT

Onboarding sequences & win-backs

Day 0 welcome, day 2 nudge if they haven’t created a project, day 7 case study, stop the moment they convert.

Here it’s a Cloudflare Workflow running in your own account: durable steps, day-long waits that cost nothing while sleeping, branching on your own events, and a live count at every node. Automations docs →

WORKFLOW · onboarding_v3
triggeruser.signed_up1,204 entered
sendtpl_welcome99.7% delivered
wait2 days318 sleeping
branchcontact.projects == 0
├─ send tpl_nudge412 sent
└─ exit792 converted
wait5 days
sendtpl_case_study86 sent
05 · MARKETING

Newsletters & product announcements

A visual editor your marketer can use, live segments your engineers can query, A/B tests that promote the winner on their own, and unsubscribe handling that keeps you the right side of CAN-SPAM.

  • Create in the API or the editor — editable in both
  • Throttle per minute, pause and resume mid-send
  • One-click list-unsubscribe headers and a preference centre
September changelogsending
18,402 of 28,700 · 5,000/min
42.1%Opens
9.8%Clicks
0.11%Unsub
BWinner
06 · INBOUND

Support inbox & reply-by-email

Receiving is free on Cloudflare Email Routing, so “email us back” stops being a feature request. Threads, attachments and search live in a Durable Object per mailbox.

Sub-addressing

[email protected] routes a reply straight back to the right object, with HMAC-signed headers.

Parsed to JSON

Headers, text, HTML, spam score and attachment keys — one webhook, no MIME parsing in your app.

Ticketing without a ticket tool

Assignment, status and canned replies are in the dashboard. See it →

07 · NEW

Email for AI agents

Agents need a real address: to receive, to read a thread, and to send only when a human says yes. That is an MCP endpoint with nine tools, an API key for a credential, and a confirmation a person approves in the dashboard before anything leaves.

  • Mark a mailbox Agent and it is the only one an agent can read
  • Sending returns a confirmation first — you approve it, not the agent
  • Works from Claude, Cursor or your own runtime
MCP · nine tools
toolssearch_threads · read_message · draft_reply
send_with_confirmation · get_delivery_status
list_contacts · add_contact · suppress · schedule
agentreads thr_5Nq → drafts reply → waits for human
auditevery action logged with the agent's key
BY STACK

Wherever your code already runs

  • Cloudflare WorkersNative binding, no HTTP hop
  • Next.js & RemixServer actions + JSX templates
  • Hono & BunTyped client, edge-first
  • Rails & DjangoSMTP relay or native SDK
  • LaravelMail driver package
  • Go, Rust, ElixirFirst-party SDKs
  • Java & .NETMaven and NuGet packages
  • WordPressSMTP plugin config, five fields

Start with one job. Keep the rest for later.

Deploy it, send an OTP, and the broadcasts, automations and inbound are already sitting there when you need them.