# Email Workers API Reference

Complete API reference for Cloudflare Email Workers runtime.

## ForwardableEmailMessage Interface

The main interface passed to email handlers.

```typescript
interface ForwardableEmailMessage {
  readonly from: string; // Envelope MAIL FROM (SMTP sender)
  readonly to: string; // Envelope RCPT TO (SMTP recipient)
  readonly headers: Headers; // Web-standard Headers object
  readonly raw: ReadableStream; // Raw MIME message (single-use stream)
  readonly rawSize: number; // Total message size in bytes

  setReject(reason: string): void;
  forward(rcptTo: string, headers?: Headers): Promise<void>;
  reply(message: EmailMessage): Promise<void>;
}
```

### Properties

| Property  | Type           | Description                                         |
| --------- | -------------- | --------------------------------------------------- |
| `from`    | string         | Envelope sender (SMTP MAIL FROM) - use for security |
| `to`      | string         | Envelope recipient (SMTP RCPT TO)                   |
| `headers` | Headers        | Message headers (Subject, Message-ID, etc.)         |
| `raw`     | ReadableStream | Raw MIME message (**single-use**, buffer first)     |
| `rawSize` | number         | Message size in bytes                               |

### Methods

#### setReject(reason: string): void

Reject with permanent SMTP 5xx error. Email not delivered, sender may receive bounce.

```typescript
if (blockList.includes(message.from)) {
  message.setReject("Sender blocked");
}
```

#### forward(rcptTo: string, headers?: Headers): Promise<void>

Forward to verified destination. Only `X-*` custom headers allowed.

```typescript
await message.forward("inbox@example.com");

// With custom headers
const h = new Headers();
h.set("X-Processed-By", "worker");
await message.forward("inbox@example.com", h);
```

#### reply(message: EmailMessage): Promise<void>

Send a reply to the original sender (March 2025 feature).

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

const msg = createMimeMessage();
msg.setSender({ name: "Support", addr: "support@example.com" });
msg.setRecipient(message.from);
msg.setSubject(`Re: ${message.headers.get("Subject")}`);
msg.setHeader("In-Reply-To", message.headers.get("Message-ID"));
msg.setHeader("References", message.headers.get("References") || "");
msg.addMessage({
  contentType: "text/plain",
  data: "Thank you for your message.",
});

await message.reply(new EmailMessage("support@example.com", message.from, msg.asRaw()));
```

**Requirements**:

- Incoming email needs valid DMARC
- Reply once per event, recipient = `message.from`
- Sender domain = receiving domain, with DMARC/SPF/DKIM
- Max 100 `References` entries
- Threading: `In-Reply-To` (original Message-ID), `References`, new `Message-ID`

## EmailMessage Constructor

```typescript
import { EmailMessage } from 'cloudflare:email';

new EmailMessage(from: string, to: string, raw: ReadableStream | string)
```

Used for sending emails (replies or via SendEmail binding). Domain must be verified.

## SendEmail Interface

```typescript
interface SendEmail {
  send(message: EmailMessage): Promise<void>;
}

// Usage
await env.EMAIL.send(new EmailMessage(from, to, mimeContent));
```

## SendEmail Binding Types

```jsonc
{
  "send_email": [
    { "name": "EMAIL" }, // Type 1: Any verified address
    { "name": "LOGS", "destination_address": "logs@example.com" }, // Type 2: Single dest
    { "name": "TEAM", "allowed_destination_addresses": ["a@ex.com", "b@ex.com"] }, // Type 3: Dest allowlist
    { "name": "NOREPLY", "allowed_sender_addresses": ["noreply@ex.com"] }, // Type 4: Sender allowlist
  ],
}
```

## postal-mime Parsed Output

postal-mime v2.7.3 parses incoming emails into structured data.

```typescript
interface ParsedEmail {
  headers: Array<{ key: string; value: string }>;
  from: { name: string; address: string } | null;
  to: Array<{ name: string; address: string }> | { name: string; address: string } | null;
  cc: Array<{ name: string; address: string }> | null;
  bcc: Array<{ name: string; address: string }> | null;
  subject: string;
  messageId: string | null;
  inReplyTo: string | null;
  references: string | null;
  date: string | null;
  html: string | null;
  text: string | null;
  attachments: Array<{
    filename: string;
    mimeType: string;
    disposition: string | null;
    related: boolean;
    contentId: string | null;
    content: Uint8Array;
  }>;
}
```

### Usage

```typescript
import PostalMime from "postal-mime";

const buffer = await new Response(message.raw).arrayBuffer();
const email = await PostalMime.parse(buffer);

console.log(email.subject);
console.log(email.from?.address);
console.log(email.text);
console.log(email.attachments.length);
```

## mimetext API Quick Reference

mimetext v3.0.27 composes outgoing emails.

```typescript
import { createMimeMessage } from "mimetext";

const msg = createMimeMessage();

// Sender
msg.setSender({ name: "John Doe", addr: "john@example.com" });

// Recipients
msg.setRecipient("alice@example.com");
msg.setRecipients(["bob@example.com", "carol@example.com"]);
msg.setCc("manager@example.com");
msg.setBcc(["audit@example.com"]);

// Headers
msg.setSubject("Meeting Notes");
msg.setHeader("In-Reply-To", "<previous-message-id>");
msg.setHeader("References", "<msg1> <msg2>");
msg.setHeader("Message-ID", `<${crypto.randomUUID()}@example.com>`);

// Content
msg.addMessage({
  contentType: "text/plain",
  data: "Plain text content",
});

msg.addMessage({
  contentType: "text/html",
  data: "<p>HTML content</p>",
});

// Attachments
msg.addAttachment({
  filename: "report.pdf",
  contentType: "application/pdf",
  data: pdfBuffer, // Uint8Array or base64 string
});

// Generate raw MIME
const raw = msg.asRaw(); // Returns string
```

## TypeScript Types

```typescript
import { ForwardableEmailMessage, EmailMessage } from "cloudflare:email";

interface Env {
  EMAIL: SendEmail;
  EMAIL_ARCHIVE: KVNamespace;
  ALLOWED_SENDERS: KVNamespace;
}

export default {
  async email(message: ForwardableEmailMessage, env: Env, ctx: ExecutionContext): Promise<void> {
    // Fully typed
  },
};
```
