Skip to content
BoringStack
GitHub

Cloudflare Email Service

3 min read

Outbound email

The apps/api ships Cloudflare Email Service as the default outbound mail provider. Bundled into Workers Paid with no documented per-message charge, it is usually the cheapest transactional path at non-trivial volume among the providers wired into this template.

Zero

per-message cost

Pluggable

providers

Beta

release status

Outbound Email Provider Comparison
Provider
Cost Dynamics
Setup Path
Preconditions
Cloudflare Email
Workers Paid bundle ($5/mo flat; zero per-message cost)
Auto-provisioned SPF/DKIM/DMARC
DNS zone must be managed on Cloudflare
Resend
Free tier, then pay-per-message usage
Manual DNS TXT records validation
None (vendor-neutral API key)
SendGrid
Free tier, then pay-per-message usage
Manual DNS TXT records validation
None (vendor-neutral API key)

Pricing tiers, free-tier limits, and per-message rates all evolve. See Cloudflare · Resend · SendGrid for current numbers.

If you’re already paying for Workers, Cloudflare Email has no per-message cost. BoringStack defaults to it because marginal cost is zero.

The API app’s email layer is pluggable: one IEmailService interface, five concrete implementations (Cloudflare, Resend, SendGrid, SMTP, noop). The Cloudflare provider POSTs to an account-scoped endpoint on api.cloudflare.com with a bearer token. Retries, structured logging, and the shared retryWithBackoff wrapper apply equally to all providers; Cloudflare gets the same reliability treatment as Resend. For local template iteration, set EMAIL_PROVIDER=smtp with SMTP_HOST=mailpit and the Mailpit overlay catches everything for inspection.

See Email for the abstraction shape and how dispatch works.

Dev with no Cloudflare keys → the noop provider logs the rendered payload to stdout instead of sending.

To actually send from dev, inject the following secrets:

Configure Local Development outbound Mail
$ echo 'EMAIL_PROVIDER=cloudflare' >> compose/.env
$ echo 'EMAIL_FROM=noreply@yourdomain.com' >> compose/.env
$ echo 'CLOUDFLARE_ACCOUNT_ID=your_account_id' >> compose/.env
$ echo 'CLOUDFLARE_EMAIL_API_TOKEN=your_scoped_api_token' >> compose/.env

The step-by-step walkthrough lives in the Cloudflare Email setup runbook: enable Workers Paid, enable Email Service on your domain, capture the account ID, scope a token, smoke-test.

Change env vars to switch to Resend or SendGrid:

Switch Outbound Mail Provider
$ echo 'EMAIL_PROVIDER=resend' >> compose/.env
$ echo 'RESEND_API_KEY=re_your_resend_api_key' >> compose/.env

Or for SendGrid:

Switch Provider to SendGrid
$ echo 'EMAIL_PROVIDER=sendgrid' >> compose/.env
$ echo 'SENDGRID_API_KEY=SG.your_sendgrid_key' >> compose/.env

The env validator refuses to boot in production if the matching key is missing; switching providers is a one-redeploy operation, not a code change.

  • Cloudflare Email Service is in beta. Pricing may evolve; daily limits are variable and account-scoped.
  • DNS must be on Cloudflare. Auto-provisioned SPF/DKIM/DMARC are how deliverability works; you can’t skip the step.
  • New accounts can only send to verified addresses until upgraded. The runbook covers the unlock.