Matrix: M22
Open in panel — /app/sending
Sending

Custom Headers

Custom headers let you embed metadata, tracking signals, and unsubscribe mechanisms into every outgoing message. PostMTA handles RFC 7230 formatting automatically and provides built-in protection against header injection attacks.

Adding Custom Headers via API

Pass custom headers in the headers object of the JSON payload. PostMTA serializes them into the message MIME tree before delivery.

curl -X POST https://api.postmta.com/v1/messages/send \
  -H "Authorization: Bearer pmk_live_abc123xyz789..." \
  -H "Content-Type: application/json" \
  -d '{
    "from": { "address": "hello@mail.example.com" },
    "to": [ { "address": "alice@example.com" } ],
    "subject": "Your order confirmation",
    "html": "<p>Order confirmed.</p>",
    "headers": {
      "X-Order-ID": "12345",
      "X-Campaign-Code": "SUMMER24",
      "X-Mailer": "PostMTA/1.0"
    }
  }'

The resulting MIME headers in the delivered message look like:

From: hello@mail.example.com
To: alice@example.com
Subject: Your order confirmation
X-Order-ID: 12345
X-Campaign-Code: SUMMER24
X-Mailer: PostMTA/1.0
Content-Type: text/html; charset="UTF-8"

[message body]

Adding headers via SMTP

For SMTP submissions, add headers directly in the message body before the blank line that separates headers from the body:

DATA
From: hello@mail.example.com
To: alice@example.com
Subject: Your order confirmation
X-Order-ID: 12345
X-Campaign-Code: SUMMER24
Content-Type: text/html; charset="UTF-8"

<html>
<body>
<p>Order confirmed.</p>
</body>
</html>
.

Required Headers (Auto-Added)

The following headers are always set by PostMTA and must not be duplicated in your payload. Attempting to override them via headers results in a 400 Bad Request validation error.

HeaderSourceNotes
FromEnvelope MAIL FROMSet from the from.address JSON field or SMTP envelope.
ToEnvelope RCPT TOSet from the to[].address JSON field or SMTP envelope.
SubjectJSON subject fieldValidated for UTF-8 encoding.
Message-IDPostMTA generatedUnique per message. Format: <msg_id@postmta.com>
DatePostMTA generatedUTC timestamp of message acceptance.
DKIM-SignaturePostMTA generatedPresent if domain DKIM is verified. Do not set manually.

List-Unsubscribe and List-Unsubscribe-Post

List-Unsubscribe is required for bulk commercial email in many jurisdictions (CAN-SPAM, CASL). It provides recipients with a one-click unsubscribe mechanism that automatically processes opt-out requests.

List-Unsubscribe header

The List-Unsubscribe header specifies the URL a recipient clicks to unsubscribe. For mail clients that render an unsubscribe button, use the mailto: form as a fallback:

"headers": {
  "List-Unsubscribe": "<https://example.com/unsubscribe/alice@example.com>, <mailto:unsubscribe@mail.example.com?subject=unsubscribe:alice@example.com>"
}

When rendered in an email client, the first URL in the angle brackets (the <https://...> URL) is typically used as the unsubscribe link.

List-Unsubscribe-Post header

List-Unsubscribe-Post: List-Unsubscribe=One-Click tells the mail client that the unsubscribe URL can be triggered with a single POST request (no browser redirect needed). PostMTA processes these automatically and adds the recipient to the suppression list.

"headers": {
  "List-Unsubscribe": "<https://example.com/unsubscribe/alice@example.com>",
  "List-Unsubscribe-Post": "List-Unsubscribe=One-Click"
}
Always include List-Unsubscribe for any commercial or marketing mailing. Bulk mail without a working unsubscribe mechanism risks CAN-SPAM and CASL violations.

X-Priority and X-Mailer Headers

X-Priority

X-Priority signals the importance of a message to the receiving mail server and client. The value is a number from 1 to 5:

ValueLabelUse case
1HighestUrgent system alerts, security notifications.
2HighImportant business communications.
3Normal (default)Standard messages.
4LowNon-urgent informational messages.
5LowestNewsletter or marketing content.
"headers": {
  "X-Priority": "1"
}
Not all mail clients respect X-Priority. For truly urgent delivery, use a dedicated high-priority sending infrastructure and warm your sending IPs accordingly.

X-Mailer

X-Mailer identifies the software that generated the message. It is informational only and not required, but it helps with debugging and can be used for tracking purposes:

"headers": {
  "X-Mailer": "MyApp/2.1.0 (PostMTA SMTP)"
}

RFC 7230 Header Formatting Rules

PostMTA enforces RFC 7230 header field formatting. Headers that violate the specification are rejected at submission time with a400 Bad Request error.

Field name rules

Field value rules

Header length limits

Header Injection Protection

Header injection (also called CRLF injection) occurs when an attacker injects unauthorized CRLF sequences into header values to smuggle additional headers or control the message body. PostMTA neutralizes this attack vector at the input validation layer.

Injection attack examples

Suppose an attacker controls the X-Custom header value and submits:

X-Custom: legitimate-value
X-Injected: attacker-controlled-header
From: attacker@evil.com

PostMTA detects any bare CR, LF, orCRLF sequence appearing within a header value that is not part of a valid encoded word or URL and rejects the submission:

{
  "error": "invalid_header",
  "message": "Header field value contains an illegal CRLF sequence. Header injection attempt detected."
}

Safely encoding special characters

For URL values that naturally contain &, ?, or =, use percent-encoding or place the URL inside angle brackets (which is the correct format for addr-spec and URL contexts):

"List-Unsubscribe": "<https://example.com/unsubscribe?token=abc123&user=alice@example.com>"

The & inside a URL in an angle-bracketed context is permitted. A bare & in an unbracketed header value is also permitted since it is not a CRLF sequence.

PostMTA's header injection protection operates on the raw header field values after parsing. Valid URLs and email addresses are not affected. Only bare CR, LF, or CRLF sequences that would allow header folding are blocked.

Next Steps