This site is not affiliated with or endorsed by Cloudflare, Inc. It simply showcases experiments built using Cloudflare services.
Cloudflare Experiments
Stateful & Async

Transactional Email

Send transactional email via the Cloudflare Email Service binding

Send transactional email via the Cloudflare Email Service send_email binding (EMAIL). Pair with Email Worker Inbox for the receive side.

API Reference

POST /send

Send an email. Provide text and/or html body content.

to string (required)

Recipient email address.

subject string (required)

Subject line.

text string (optional)

Plain-text body (at least one of text or html required).

html string (optional)

HTML body (at least one of text or html required).

Example Request

curl -X POST "https://your-worker.workers.dev/send" \
  -H "Content-Type: application/json" \
  -d '{"to":"[email protected]","subject":"Welcome","text":"Thanks for signing up."}'

Success Response

{
  "sent": true,
  "to": "[email protected]",
  "subject": "Welcome",
  "messageId": "..."
}

Error Codes

  • 400 - Invalid to, subject, body, or JSON (INVALID_TO, INVALID_SUBJECT, MISSING_BODY, INVALID_BODY)
  • 502 - Email send failure (SEND_ERROR)

Use Cases

  • Learn the Email Sending / send_email binding
  • Transactional welcome, reset, and notification emails
  • Restrict destinations with destination_address during demos
  • Pair with Email Worker Inbox for end-to-end mail experiments

Limitations

  • Requires onboarding a sending domain (wrangler email sending enable)
  • FROM_EMAIL must be on that domain
  • Optional destination_address on the binding can lock recipients for demos
  • No queueing or retry UI in this minimal experiment

Use in your project

Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/transactional-email.

DependenciesNoneBindingsEmailPlatformWorkers runtime
import {  DEFAULT_FROM_EMAIL,  EMAIL_PATTERN,  MAX_BODY_LENGTH,  MAX_SUBJECT_LENGTH,} from "../constants/defaults";import type { Env } from "../types/env";import type { SendEmailRequest, SendEmailResponse } from "../types/email";export function validateEmail(input: string | undefined): string | null {  if (!input || typeof input !== "string") return null;  const trimmed = input.trim();  if (!EMAIL_PATTERN.test(trimmed)) return null;  return trimmed;}export function validateSubject(input: string | undefined): string | null {  if (!input || typeof input !== "string") return null;  const trimmed = input.trim();  if (!trimmed || trimmed.length > MAX_SUBJECT_LENGTH) return null;  return trimmed;}export function validateBodyField(input: string | undefined): string | null {  if (input === undefined || input === null) return null;  if (typeof input !== "string") return null;  if (!input.trim() || input.length > MAX_BODY_LENGTH) return null;  return input;}export async function sendTransactionalEmail(  env: Env,  request: Required<Pick<SendEmailRequest, "to" | "subject">> &    Pick<SendEmailRequest, "text" | "html">): Promise<SendEmailResponse> {  const from = env.FROM_EMAIL?.trim() || DEFAULT_FROM_EMAIL;  const result = await env.EMAIL.send({    from,    to: request.to,    subject: request.subject,    text: request.text,    html: request.html,  });  return {    sent: true,    to: request.to,    subject: request.subject,    messageId: result.messageId,  };}

Deployment

Click the deploy button

Deploy to Cloudflare Workers

Configure Email Sending

  1. Onboard a sending domain: npx wrangler email sending enable yourdomain.com
  2. Set FROM_EMAIL in wrangler.json vars to an address on that domain
  3. Optionally restrict destinations with destination_address on the EMAIL binding

Test your deployment

curl -X POST "https://your-worker.workers.dev/send" \
  -H "Content-Type: application/json" \
  -d '{"to":"[email protected]","subject":"Welcome","text":"Thanks for signing up."}'

Local Development

cd apps/experiments/transactional-email
npm install
npm run dev
curl -X POST "http://localhost:8787/send" \
  -H "Content-Type: application/json" \
  -d '{"to":"[email protected]","subject":"Welcome","text":"Thanks for signing up."}'

Configuration

wrangler.json declares:

  • send_email binding EMAIL (optional destination_address)
  • Var FROM_EMAIL

Cloudflare Features Used

On this page