Documentation Schedule a pilot

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.

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

  1. Header names — ASCII only, no spaces, no colons, 1–100 characters. Allowlisted headers must match [A-Za-z0-9\-]+. X-headers must match X-[A-Za-z0-9\-_]+ (underscores allowed only in X-headers).
  2. Header values — UTF-8 allowed, maximum 2,048 bytes, no bare CR/LF. Empty values are rejected.
  3. 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.
  4. Proper line folding — Long headers are folded at 78 characters per RFC 5322 using CRLF+WSP, not MIME encoding.
  5. Single occurrence — The headers type is { [key]: string }, so each header name can appear at most once. For headers that support multiple values (such as Keywords or Comments), 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.

Request your free pilot

Schedule a pilot