← Email Service / email-service / reference
Email headers
When sending emails with Cloudflare Email Service, you can set custom headers using the headers field in the Workers API or REST API. The Email Service uses a allowlist-based approach — only explicitly approved headers are accepted. Any header not on the allowlist (and not an X- prefixed custom header) is rejected at API time with a clear error.
When sending over SMTP, set headers directly in the MIME message rather than through a headers field. The same allowlist applies.
Platform-controlled headers
These headers are auto-generated by the Cloudflare Email Service infrastructure. You cannot set or override them. If you include any of these in the headers object, the API returns E_HEADER_NOT_ALLOWED.
| Header | Behavior |
|---|---|
Date |
UTC timestamp set at acceptance time |
Message-ID |
Generated with Cloudflare domain for unique tracking |
MIME-Version |
Always 1.0 |
Content-Type |
Generated from body parts provided |
Content-Transfer-Encoding |
Generated from content analysis |
DKIM-Signature |
Signed by Cloudflare infrastructure |
Return-Path |
Set to Cloudflare bounce processor |
Received |
Added per RFC 5321 at each hop |
Feedback-ID |
Generated for Google Postmaster Tools reputation feedback |
ARC-* |
Authentication chain for forwarding |
TLS-Required |
Platform-controlled delivery infrastructure setting |
TLS-Report-Domain |
TLS failure reports route to Cloudflare infrastructure |
TLS-Report-Submitter |
References Cloudflare sending domain |
CFBL-Address |
Complaint feedback loop address (RFC 9477) |
CFBL-Feedback-ID |
Complaint feedback loop ID (RFC 9477) |
Headers that correspond to first-class API fields — From, To, Cc, Bcc, Subject, Reply-To — are also rejected in the headers object with E_HEADER_USE_API_FIELD. Set these using the dedicated API fields (from, to, cc, bcc, subject, replyTo for Workers / reply_to for REST) instead.
Allowlisted custom headers
These headers can be set via the headers field. Any header not listed here and not starting with X- is rejected with E_HEADER_NOT_ALLOWED.
Email Service rejects the entire send request if it contains a disallowed header. It does not remove the header and continue sending the message.
Threading and reply headers
| Header | RFC | Notes |
|---|---|---|
In-Reply-To |
RFC 5322 ↗ | Critical for email threading in all clients |
References |
RFC 5322 ↗ | Critical for email threading in all clients |
Thread-Index |
Microsoft (non-standard) | Conversation index used by Outlook and Exchange Online |
Thread-Topic |
Microsoft (non-standard) | Conversation subject used by Outlook and Exchange Online |
List management headers
| Header | RFC | Notes |
|---|---|---|
List-Unsubscribe |
RFC 2369 ↗ | Must contain <https://...> and/or <mailto:...> URI(s). HTTP (non-TLS) URIs are rejected. Gmail and Yahoo require this for bulk senders. Always DKIM-signed per RFC 8058. |
List-Unsubscribe-Post |
RFC 8058 ↗ | Must be exactly List-Unsubscribe=One-Click (case-sensitive). Requires List-Unsubscribe with an HTTPS URI. |
List-Id |
RFC 2919 ↗ | List identification |
List-Archive |
RFC 2369 ↗ | URL to list archive |
List-Help |
RFC 2369 ↗ | URL for help |
List-Owner |
RFC 2369 ↗ | List owner contact |
List-Post |
RFC 2369 ↗ | Address for posting |
List-Subscribe |
RFC 2369 ↗ | Subscribe URL or address |
Precedence |
De facto standard | Accepted values: bulk, list, junk |
Automated message identification
| Header | RFC | Notes |
|---|---|---|
Auto-Submitted |
RFC 3834 ↗ | Values: auto-generated, auto-replied, auto-notified |
Content and display
| Header | RFC | Notes |
|---|---|---|
Content-Language |
RFC 3282 ↗ | Language of content (for example, en, fr) |
Keywords |
RFC 5322 ↗ | Message keywords (comma-separated for multiple values) |
Comments |
RFC 5322 ↗ | Additional comments (comma-separated for multiple values) |
Importance |
RFC 2156 ↗ | Values: high, normal, low |
Priority |
RFC 2156 ↗ | Values: normal, non-urgent, urgent |
Sensitivity |
RFC 2156 ↗ | Values: personal, private, company-confidential |
Organization |
RFC 4021 ↗ | Sender's organization name |
Delivery and notification
| Header | RFC | Notes |
|---|---|---|
Require-Recipient-Valid-Since |
RFC 7293 ↗ | Address reuse protection |
Expires |
RFC 2156 ↗ | Date and time after which the message is no longer valid |
Reply-By |
RFC 2156 ↗ | Date and time by which a reply is requested |
Modern standards
| Header | RFC | Notes |
|---|---|---|
Archived-At |
RFC 5064 ↗ | URL where message is archived |
Custom X-headers
Any header starting with X- is allowed. This covers common headers like X-Mailer, X-Priority, X-Campaign-ID, and any custom tracking headers your application needs.
- Name format:
X-[A-Za-z0-9\-_]+, maximum 100 characters - Value: UTF-8, maximum 2,048 bytes
- No count limit on X-headers (subject to the 16 KB total payload limit)
Usage examples
curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/email/sending/send" \
--header "Authorization: Bearer <API_TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"to": "user@example.com",
"from": "notifications@yourdomain.com",
"subject": "Your weekly digest",
"html": "<h1>Weekly Digest</h1>",
"headers": {
"In-Reply-To": "<original-message-id@yourdomain.com>",
"References": "<original-message-id@yourdomain.com>",
"List-Unsubscribe": "<https://yourdomain.com/unsubscribe?id=abc123>",
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
"X-Campaign-ID": "weekly-digest-2026-03",
"X-User-Segment": "premium"
}
}'const response = await env.EMAIL.send({
to: "user@example.com",
from: "notifications@yourdomain.com",
subject: "Your weekly digest",
html: "<h1>Weekly Digest</h1>",
headers: {
// Threading
"In-Reply-To": "<original-message-id@yourdomain.com>",
References: "<original-message-id@yourdomain.com>",
// List management (required by Gmail/Yahoo for bulk senders)
"List-Unsubscribe": "<https://yourdomain.com/unsubscribe?id=abc123>",
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
// Custom tracking
"X-Campaign-ID": "weekly-digest-2026-03",
"X-User-Segment": "premium",
},
});Header limits
| Limit | Value |
|---|---|
| Max allowlisted (non-X) custom headers | 20 |
| Max header name length | 100 bytes |
| Max header value length | 2,048 bytes |
| Total custom headers payload | 16 KB |
The total payload is calculated as sum(len(name) + 2 + len(value) + 2) for all custom headers (name + : + value + CRLF). Allowlisted and X-headers are counted together toward this limit.
Validation rules
- Header names — ASCII only, no spaces, no colons, 1–100 characters. Allowlisted headers must match
[A-Za-z0-9\-]+. X-headers must matchX-[A-Za-z0-9\-_]+(underscores allowed only in X-headers). - Header values — UTF-8 allowed, maximum 2,048 bytes, no bare CR/LF. Empty values are rejected.
- Case-insensitive matching — Header names are matched case-insensitively per RFC 5322 §2.2 ↗. The canonical casing from the allowlist is used in the generated message.
- Proper line folding — Long headers are folded at 78 characters per RFC 5322 using CRLF+WSP, not MIME encoding.
- Single occurrence — The
headerstype is{ [key]: string }, so each header name can appear at most once. For headers that support multiple values (such asKeywordsorComments), use comma-separated values in a single string.
Error codes
| Error Code | When | Example message |
|---|---|---|
E_HEADER_NOT_ALLOWED |
Header is platform-controlled or not on the allowlist | Header 'Date' is not allowed. It is auto-generated by the platform. |
E_HEADER_USE_API_FIELD |
Header corresponds to a first-class API field | Header 'From' must be set via the 'from' API field, not the 'headers' object. |
E_HEADER_VALUE_INVALID |
Header value is malformed or empty | Header 'List-Unsubscribe' must contain angle-bracket HTTPS or mailto URI(s). |
E_HEADER_VALUE_TOO_LONG |
Header value exceeds 2,048 byte limit | Header 'X-Campaign-ID' value exceeds 2048 byte limit. |
E_HEADER_NAME_INVALID |
Header name contains invalid characters or exceeds 100 bytes | Header name 'Bad Header!' contains invalid characters. |
E_HEADERS_TOO_LARGE |
Total custom headers payload exceeds 16 KB | Total custom headers payload (17.2KB) exceeds 16KB limit. |
E_HEADERS_TOO_MANY |
Too many allowlisted (non-X) custom headers | 21 allowlisted headers provided, maximum is 20. |