---
description: Send emails directly from Cloudflare Workers using the Email Service binding and send() method.
title: Workers API
image: https://developers.cloudflare.com/og-docs.png
---

[Skip to content](#main-content)

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/email-service/llms.txt  
> Use this file to discover all available pages before exploring further.

# Workers API

Last updated Aug 25, 2026|Copy as Markdown| [View as Markdown](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/api/send-emails/workers-api/index.md)| [Agent setup](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/agent-setup/)

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](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/api/send-emails/rest-api/) instead.

## Email binding

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

```jsonc
{
	"send_email": [{ "name": "EMAIL" }],
}
```

```toml
[[send_email]]
name = "EMAIL"
```

You can restrict which senders and recipients a binding may use. Refer to [Configure send bindings](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/configuration/send-bindings/) for the available restriction attributes and examples.

## `send()` method

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

### Interface

```ts
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) }
```

Local development with binary attachments

When using `wrangler dev` without [remote bindings](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/workers/local-development/#remote-bindings), `ArrayBuffer` and `ArrayBufferView` content in attachments cannot be serialized by the local simulator. Refer to [local development for email sending](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/local-development/sending/#known-limitations).

### Basic usage

```ts
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](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/examples/email-sending/recipients/).

### Attachments

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

```ts
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](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/examples/email-sending/email-attachments/).

## Error handling

Handle email sending errors gracefully:

```ts
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](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/reference/headers/) |
| `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 ↗](https://datatracker.ietf.org/doc/html/rfc5322) MIME message to send. For new code, prefer the structured [`send()` method](#send-method) above.

```ts
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

- See the [REST API](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/api/send-emails/rest-api/) for sending emails without Workers
- See [SMTP](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/api/send-emails/smtp/) for sending from any SMTP-capable application or mail client
- See [practical examples](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/examples/) of email sending patterns
- Learn about [email routing](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/api/route-emails/) for handling incoming emails
- Explore [email authentication](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/email-service/concepts/email-authentication/) for better deliverability

Was this helpful?

YesNo

## On this page

[![](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://d1-custom-bindings-docs.previews.developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/email-service/api/send-emails/workers-api/#page","headline":"Workers API · Cloudflare Email Service docs","description":"Send emails directly from Cloudflare Workers using the Email Service binding and send() method.","url":"https://developers.cloudflare.com/email-service/api/send-emails/workers-api/","inLanguage":"en","image":"https://developers.cloudflare.com/og-docs.png","dateModified":"2026-08-25","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
