Pular para o conteúdo

Workers API

Atualizado em Ver como Markdown

The Workers API provides native email sending capabilities directly from your Cloudflare Workers through bindings. If you are not using Workers, you can send emails using the REST API instead.

Email binding

Configure a send_email binding in your Wrangler configuration file to enable email sending:

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

You can restrict which senders and recipients a binding may use. Refer to Configure send bindings for the available restriction attributes and examples.

send() method

Send a single email using the send() method on your email binding.

Interface

interface SendEmail {
	send(message: EmailMessage | EmailMessageBuilder): Promise<EmailSendResult>;
}

interface EmailAddress {
	email: string;
	name?: string;
}

// Structured email builder (recommended)
interface EmailMessageBuilder {
	to: string | EmailAddress | (string | EmailAddress)[]; // Max 50 recipients
	from: string | EmailAddress;
	subject: string;
	html?: string;
	text?: string;
	cc?: string | EmailAddress | (string | EmailAddress)[];
	bcc?: string | EmailAddress | (string | EmailAddress)[];
	replyTo?: string | EmailAddress;
	attachments?: Attachment[];
	// Custom headers. See /email-service/reference/headers/
	headers?: { [key: string]: string };
	// The combined number of addresses in `to`, `cc`, and `bcc` must not
	// exceed 50. See /email-service/platform/limits/ for all limits.
}

interface Attachment {
	content: string | ArrayBuffer | ArrayBufferView; // Base64 string or binary content
	filename: string;
	type: string; // MIME type
	disposition: "attachment" | "inline";
	contentId?: string; // For inline attachments
}

interface EmailSendResult {
	messageId: string; // Unique email ID
}

// Errors are thrown as standard Error objects with a `code` property
// try { await env.EMAIL.send(...) } catch (e) { console.log(e.code, e.message) }

Basic usage

const response = await env.EMAIL.send({
	to: "recipient@example.com",
	from: "welcome@yourdomain.com",
	subject: "Welcome to our service!",
	html: "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
	text: "Welcome! Thanks for signing up.",
});

For multiple recipients, CC/BCC, and named addresses, see Specify recipients.

Attachments

Send files by including base64-encoded content in the attachments array. The total message size must not exceed 5 MiB (including attachments).

const response = await env.EMAIL.send({
	to: "customer@example.com",
	from: "invoices@yourdomain.com",
	subject: "Your Invoice",
	html: "<h1>Invoice attached</h1><p>Please find your invoice attached.</p>",
	attachments: [
		{
			content: "JVBERi0xLjQKJeLjz9MKMSAwIG9iag...", // Base64 PDF content
			filename: "invoice-12345.pdf",
			type: "application/pdf",
			disposition: "attachment",
		},
	],
});

For inline images and file uploads, see Email attachments.

Error handling

Handle email sending errors gracefully:

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		try {
			const response = await env.EMAIL.send({
				to: "user@example.com",
				from: "noreply@yourdomain.com",
				subject: "Test Email",
				text: "This is a test email.",
			});

			return new Response(
				JSON.stringify({
					success: true,
					emailId: response.messageId,
				}),
			);
		} catch (error) {
			// Error has .code and .message properties
			console.error("Email sending failed:", error.code, error.message);

			// Handle specific error types
			switch (error.code) {
				case "E_SENDER_NOT_VERIFIED":
					return new Response(
						JSON.stringify({
							success: false,
							error: "Please verify your sender domain first",
						}),
						{ status: 400 },
					);

				case "E_RATE_LIMIT_EXCEEDED":
					return new Response(
						JSON.stringify({
							success: false,
							error: "Rate limit exceeded. Please try again later",
						}),
						{ status: 429 },
					);

				default:
					return new Response(
						JSON.stringify({
							success: false,
							error: error.message,
						}),
						{ status: 500 },
					);
			}
		}
	},
};

Error codes

The following error codes may be returned when sending emails:

Error Code Description Common Causes
E_VALIDATION_ERROR Validation error in the payload Invalid email format, missing required fields, malformed data
E_FIELD_MISSING Required field is missing Missing to, from, or subject fields
E_TOO_MANY_RECIPIENTS Too many recipients in to/cc/bcc arrays Combined recipients exceed 50 limit
E_TOO_MANY_ATTACHMENTS Too many attachments in attachments array attachments array exceeds 32 entries
E_SENDER_NOT_VERIFIED Sender domain not verified Attempting to send from unverified domain
E_RECIPIENT_NOT_ALLOWED Recipient not in allowed list Recipient address not in allowed_destination_addresses
E_RECIPIENT_SUPPRESSED Recipient is on suppression list Email address has bounced or reported your emails as spam
E_SENDER_DOMAIN_NOT_AVAILABLE Domain not available for sending Domain not onboarded to Email Service
E_CONTENT_TOO_LARGE Email content exceeds size limit Total message size exceeds the maximum
E_DELIVERY_FAILED Could not deliver the email SMTP delivery failure, recipient server rejection
E_RATE_LIMIT_EXCEEDED Rate limit exceeded Sending rate limit reached
E_DAILY_LIMIT_EXCEEDED Daily limit exceeded Daily sending quota reached
E_INTERNAL_SERVER_ERROR Internal service error Email Service temporarily unavailable
E_HEADER_NOT_ALLOWED Header not allowed Header is platform-controlled or not on the allowlist
E_HEADER_USE_API_FIELD Must use API field Header like From must be set via the dedicated API field
E_HEADER_VALUE_INVALID Header value invalid Malformed value, empty, or incorrect format
E_HEADER_VALUE_TOO_LONG Header value too long Value exceeds 2,048 byte limit
E_HEADER_NAME_INVALID Header name invalid Invalid characters or exceeds 100 byte limit
E_HEADERS_TOO_LARGE Headers payload too large Total custom headers exceed 16 KB limit
E_HEADERS_TOO_MANY Too many headers More than 20 allowlisted (non-X) custom headers

Legacy EmailMessage API

The EmailMessage API remains supported for backward compatibility. Use it when you already have a raw RFC 5322 MIME message to send. For new code, prefer the structured send() method above.

import { EmailMessage } from "cloudflare:email";
import { createMimeMessage } from "mimetext";

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		const msg = createMimeMessage();
		msg.setSender({ name: "Sender", addr: "sender@yourdomain.com" });
		msg.setRecipient("recipient@example.com");
		msg.setSubject("Legacy Email");
		msg.addMessage({
			contentType: "text/html",
			data: "<h1>Hello from legacy API</h1>",
		});

		const message = new EmailMessage(
			"sender@yourdomain.com",
			"recipient@example.com",
			msg.asRaw(),
		);

		await env.EMAIL.send(message);
		return new Response("Legacy email sent");
	},
};

Next steps