Email Workers API Reference
Complete API reference for Cloudflare Email Workers runtime.
ForwardableEmailMessage Interface
The main interface passed to email handlers.
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.
if (blockList.includes(message.from)) {
message.setReject('Sender blocked')
}
forward(rcptTo: string, headers?: Headers): Promise
Forward to verified destination. Only X-* custom headers allowed.
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
Send a reply to the original sender (March 2025 feature).
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
Referencesentries - Threading:
In-Reply-To(original Message-ID),References, newMessage-ID
EmailMessage Constructor
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
interface SendEmail {
send(message: EmailMessage): Promise<void>
}
// Usage
await env.EMAIL.send(new EmailMessage(from, to, mimeContent))
SendEmail Binding Types
{
"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.
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
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.
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
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
},
}