Skip to main content

Overview

Cloudflare Agents provides utilities for routing incoming emails to Agent instances with support for address-based routing, secure reply flows, and catch-all patterns.

routeAgentEmail()

Route an email to the appropriate Agent.
ForwardableEmailMessage
required
The email to route (from Email Workers)
Env
required
Environment containing Agent bindings
EmailRoutingOptions<Env>
required
EmailResolver<Env>
required
Function that determines which Agent to route to
(email: ForwardableEmailMessage) => void | Promise<void>
Called when no routing information is found. If not provided, a warning is logged and the email is dropped.
Returns: Promise<void>

Email Resolvers

createAddressBasedEmailResolver()

Route based on email address (sub-address or local part).
string
required
Default agent name to use if email doesn’t contain sub-address
Routing patterns:
  • support+ticket123@example.comSupportAgent instance ticket123
  • support@example.comSupportAgent instance support
  • agent+room@example.comagent instance room
Returns: EmailResolver<Env>

createSecureReplyEmailResolver()

Route secure reply emails with signature verification.
string
required
Secret key for HMAC verification (must match signAgentHeaders)
SecureReplyResolverOptions
number
default:"2592000"
Maximum signature age in seconds (default: 30 days)
(email, reason) => void
Called when signature verification fails
Returns: EmailResolver<Env>
Use signAgentHeaders() when sending outbound emails to enable secure reply routing.

createCatchAllEmailResolver()

Route all emails to a single Agent instance.
string
required
Agent class name
string
required
Agent instance name
Returns: EmailResolver<Env>

Combining Resolvers

Try multiple resolvers in sequence:

Secure Reply Flow

Signing Outbound Emails

Use signAgentHeaders() to sign emails for secure reply routing:
string
required
Secret key for HMAC signing (store in environment variables)
string
required
Agent class name (kebab-case)
string
required
Agent instance name
Returns: Promise<Record<string, string>>

replyToEmail()

Reply to an email from within an Agent:
AgentEmail
required
The email to reply to
ReplyOptions
required
string
required
Sender name
string
Email subject (defaults to “Re: original subject”)
string
required
Email body
string
default:"text/plain"
MIME content type
Record<string, string>
Additional headers
string | null
Secret for signing headers. Required if email was routed via createSecureReplyEmailResolver. Pass null to opt out.
Returns: Promise<void>
If the email was routed via createSecureReplyEmailResolver, you must pass a secret to sign replies. Otherwise, replies cannot be routed back securely.

Email Utilities

isAutoReplyEmail()

Check if an email is an auto-reply (to avoid reply loops).
EmailHeader[]
required
Headers array from postal-mime or similar
Returns: boolean Checks for:
  • Auto-Submitted header (RFC 3834)
  • X-Auto-Response-Suppress header
  • Precedence: bulk/junk/list header

Email Handler

onEmail()

Override to handle incoming emails in your Agent:

AgentEmail Type

The AgentEmail object passed to onEmail():
string
required
Sender email address
string
required
Recipient email address
Headers
required
Email headers
number
required
Size of the raw email in bytes
() => Promise<Uint8Array>
required
Get the raw email content
(options) => Promise<void>
required
Send a reply (use replyToEmail() instead for automatic header signing)
(rcptTo: string, headers?: Headers) => Promise<void>
required
Forward the email to another address
(reason: string) => void
required
Reject the email with a reason

Full Example

wrangler.jsonc Configuration

Security

Signature Verification

Signatures prevent attackers from spoofing email headers to route emails to arbitrary agents:

Signature Expiration

Signatures expire after maxAge (default: 30 days):

Secret Management

Store secrets in environment variables:
Or in .dev.vars for local development:

Best Practices

Use Secure Resolvers

Check Auto-Replies

Handle No Route

Sign Replies