[ PROMPT_NODE_24097 ]
Email Routing – API
[ SKILL_DOCUMENTATION ]
# Email Routing API Reference
## Worker Runtime API
### Email Handler Interface
```typescript
interface ExportedHandler {
email?(message: ForwardableEmailMessage, env: Env, ctx: ExecutionContext): void | Promise;
}
```
### ForwardableEmailMessage
Main interface for incoming emails:
```typescript
interface ForwardableEmailMessage {
readonly from: string; // Envelope sender (e.g., "[email protected]")
readonly to: string; // Envelope recipient (e.g., "[email protected]")
readonly headers: Headers; // Web API Headers object
readonly raw: ReadableStream; // Raw MIME message stream
setReject(reason: string): void;
forward(rcptTo: string, headers?: Headers): Promise;
}
```
**Key Properties:**
| Property | Type | Description |
|----------|------|-------------|
| `from` | `string` | Envelope sender (MAIL FROM), not header From |
| `to` | `string` | Envelope recipient (RCPT TO), not header To |
| `headers` | `Headers` | Email headers (Subject, From, To, etc.) |
| `raw` | `ReadableStream` | Raw MIME message (consume once only) |
**Methods:**
- `setReject(reason)`: Reject email with bounce message
- `forward(rcptTo, headers?)`: Forward to verified destination, optionally add headers
### Headers Object
Standard Web API Headers interface:
```typescript
// Access headers
const subject = message.headers.get("subject");
const from = message.headers.get("from");
const messageId = message.headers.get("message-id");
// Check spam score
const spamScore = parseFloat(message.headers.get("x-cf-spamh-score") || "0");
if (spamScore > 5) {
message.setReject("Spam detected");
}
```
### Common Headers
`subject`, `from`, `to`, `x-cf-spamh-score` (spam score), `message-id` (deduplication), `dkim-signature` (auth)
### Envelope vs Header Addresses
**Critical distinction:**
```typescript
// Envelope addresses (routing, auth checks)
message.from // "[email protected]" (actual sender)
message.to // "[email protected]" (your address)
// Header addresses (display, user-facing)
message.headers.get("from") // "Alice "
message.headers.get("to") // "Bob "
```
**Use envelope addresses for:**
- Authentication/SPF checks
- Routing decisions
- Bounce handling
**Use header addresses for:**
- Display to users
- Reply-To logic
- User-facing filtering
## SendEmail Binding
Outbound email API for transactional messages.
### Configuration
```jsonc
// wrangler.jsonc
{
"send_email": [
{ "name": "EMAIL" }
]
}
```
### TypeScript Types
```typescript
interface Env {
EMAIL: SendEmail;
}
interface SendEmail {
send(message: EmailMessage): Promise;
}
interface EmailMessage {
from: string | { name?: string; email: string };
to: string | { name?: string; email: string } | Array;
subject: string;
text?: string;
html?: string;
headers?: Headers;
reply_to?: string | { name?: string; email: string };
}
```
### Send Email Example
```typescript
interface Env {
EMAIL: SendEmail;
}
export default {
async fetch(request, env, ctx): Promise {
await env.EMAIL.send({
from: { name: "Acme Corp", email: "[email protected]" },
to: [
{ name: "Alice", email: "[email protected]" },
"[email protected]"
],
subject: "Your order #12345 has shipped",
text: "Track your package at: https://track.example.com/12345",
html: "
Track your package at: View tracking
", reply_to: { name: "Support", email: "[email protected]" } }); return new Response("Email sent"); } } satisfies ExportedHandler; ``` ### SendEmail Constraints - **From address**: Must be on verified domain (your domain with Email Routing enabled) - **Volume limits**: Transactional only, no bulk/marketing email - **Rate limits**: 100 emails/minute on Free plan, higher on Paid - **No attachments**: Use links to hosted files instead - **No DKIM control**: Cloudflare signs automatically ## REST API Operations Base URL: `https://api.cloudflare.com/client/v4` ### Authentication ```bash curl -H "Authorization: Bearer $API_TOKEN" https://api.cloudflare.com/client/v4/... ``` ### Key Endpoints | Operation | Method | Endpoint | |-----------|--------|----------| | Enable routing | POST | `/zones/{zone_id}/email/routing/enable` | | Disable routing | POST | `/zones/{zone_id}/email/routing/disable` | | List rules | GET | `/zones/{zone_id}/email/routing/rules` | | Create rule | POST | `/zones/{zone_id}/email/routing/rules` | | Verify destination | POST | `/zones/{zone_id}/email/routing/addresses` | | List destinations | GET | `/zones/{zone_id}/email/routing/addresses` | ### Create Routing Rule Example ```bash curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/email/routing/rules" -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" -d '{ "enabled": true, "name": "Forward sales", "matchers": [{"type": "literal", "field": "to", "value": "[email protected]"}], "actions": [{"type": "forward", "value": ["[email protected]"]}], "priority": 0 }' ``` Matcher types: `literal` (exact match), `all` (catch-all).
Source: claude-code-templates (MIT). See About Us for full credits.