What are custom headers?
Custom headers let you attach RFC 5322 compliant headers to your messages. This is useful for message classification, tracking, and per-recipient identifiers.Some headers are restricted to prevent abuse, and MailChannels may limit how many times the same header can be repeated. See Restricted headers for a non-exhaustive list.
Adding custom headers
Include custom headers in the top-levelheaders object to apply them to every recipient of the message:
#!/usr/bin/env bash
set -u
: "${MAILCHANNELS_API_KEY:?Set MAILCHANNELS_API_KEY before running}"
: "${FROM_EMAIL:?Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)}"
: "${TO_EMAIL:?Set TO_EMAIL}"
curl -X POST https://api.mailchannels.net/tx/v1/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: $MAILCHANNELS_API_KEY" \
-d @- <<JSON
{
"personalizations": [
{ "to": [{ "email": "$TO_EMAIL", "name": "Recipient" }] }
],
"from": {
"email": "$FROM_EMAIL",
"name": "Your Name"
},
"subject": "Hello from MailChannels",
"content": [
{
"type": "text/plain",
"value": "Hello from MailChannels."
}
],
"headers": {
"X-Campaign-Id": "welcome-2026"
}
}
JSON
import { MailChannels } from "mailchannels-sdk";
const { MAILCHANNELS_API_KEY, FROM_EMAIL, TO_EMAIL } = process.env;
if (!MAILCHANNELS_API_KEY) throw new Error("Set MAILCHANNELS_API_KEY before running");
if (!FROM_EMAIL) throw new Error("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)");
if (!TO_EMAIL) throw new Error("Set TO_EMAIL");
const mailchannels = new MailChannels(MAILCHANNELS_API_KEY);
const { data, error } = await mailchannels.emails.send({
from: { email: FROM_EMAIL, name: "Your Name" },
to: { email: TO_EMAIL, name: "Recipient" },
subject: "Hello from MailChannels",
text: "Hello from MailChannels.",
headers: {
"X-Campaign-Id": "welcome-2026",
},
});
if (error) {
console.error("Send failed:", error);
process.exit(1);
}
console.log(data);
import os
import sys
import mailchannels
if not os.environ.get("MAILCHANNELS_API_KEY"):
sys.exit("Set MAILCHANNELS_API_KEY before running")
from_email = os.environ.get("FROM_EMAIL")
to_email = os.environ.get("TO_EMAIL")
if not from_email:
sys.exit("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)")
if not to_email:
sys.exit("Set TO_EMAIL")
response = mailchannels.Emails.send(
{
"from": {"email": from_email, "name": "Your Name"},
"to": [{"email": to_email, "name": "Recipient"}],
"subject": "Hello from MailChannels",
"text": "Hello from MailChannels.",
"headers": {
"X-Campaign-Id": "welcome-2026",
},
}
)
print(response)
<?php
require_once __DIR__ . '/vendor/autoload.php';
use MailChannels\Client;
$api_key = getenv('MAILCHANNELS_API_KEY') or exit("Error: MAILCHANNELS_API_KEY is not set\n");
$from_email = getenv('FROM_EMAIL') or exit("Error: FROM_EMAIL is not set\n");
$to_email = getenv('TO_EMAIL') or exit("Error: TO_EMAIL is not set\n");
$client = new Client(apiKey: $api_key);
$response = $client->emails->send([
'from' => ['email' => $from_email, 'name' => 'Your Name'],
'to' => ['email' => $to_email, 'name' => 'Recipient'],
'subject' => 'Hello from MailChannels',
'text' => 'Hello from MailChannels.',
'headers' => [
'X-Campaign-Id' => 'welcome-2026',
],
]);
print_r($response->toArray());
Using custom headers incorrectly could significantly harm your email deliverability.
Custom headers within personalizations
Custom headers can also be added to individual personalizations, allowing for recipient-specific headers. This is useful for personalized unsubscribe links, tracking, or identification headers that vary per recipient.#!/usr/bin/env bash
set -u
: "${MAILCHANNELS_API_KEY:?Set MAILCHANNELS_API_KEY before running}"
: "${FROM_EMAIL:?Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)}"
: "${TO_EMAIL_1:?Set TO_EMAIL_1}"
: "${TO_EMAIL_2:?Set TO_EMAIL_2}"
curl -X POST https://api.mailchannels.net/tx/v1/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: $MAILCHANNELS_API_KEY" \
-d @- <<JSON
{
"personalizations": [
{
"to": [{ "email": "$TO_EMAIL_1" }],
"headers": {
"X-Campaign-Id": "welcome-2026-cohort-a"
}
},
{
"to": [{ "email": "$TO_EMAIL_2" }],
"headers": {
"X-Campaign-Id": "welcome-2026-cohort-b"
}
}
],
"from": {
"email": "$FROM_EMAIL",
"name": "Your Name"
},
"subject": "Hello from MailChannels",
"content": [
{
"type": "text/plain",
"value": "Hello from MailChannels."
}
]
}
JSON
import { MailChannels } from "mailchannels-sdk";
const { MAILCHANNELS_API_KEY, FROM_EMAIL, TO_EMAIL_1, TO_EMAIL_2 } = process.env;
if (!MAILCHANNELS_API_KEY) throw new Error("Set MAILCHANNELS_API_KEY before running");
if (!FROM_EMAIL) throw new Error("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)");
if (!TO_EMAIL_1) throw new Error("Set TO_EMAIL_1");
if (!TO_EMAIL_2) throw new Error("Set TO_EMAIL_2");
const mailchannels = new MailChannels(MAILCHANNELS_API_KEY);
// Each personalization can carry its own headers, which override the
// top-level `headers` for that recipient.
const { data, error } = await mailchannels.emails.send({
from: { email: FROM_EMAIL, name: "Your Name" },
personalizations: [
{ to: [{ email: TO_EMAIL_1 }], headers: { "X-Campaign-Id": "welcome-2026-cohort-a" } },
{ to: [{ email: TO_EMAIL_2 }], headers: { "X-Campaign-Id": "welcome-2026-cohort-b" } },
],
subject: "Hello from MailChannels",
text: "Hello from MailChannels.",
});
if (error) {
console.error("Send failed:", error);
process.exit(1);
}
console.log(data);
import os
import sys
import mailchannels
if not os.environ.get("MAILCHANNELS_API_KEY"):
sys.exit("Set MAILCHANNELS_API_KEY before running")
from_email = os.environ.get("FROM_EMAIL")
to_email_1 = os.environ.get("TO_EMAIL_1")
to_email_2 = os.environ.get("TO_EMAIL_2")
if not from_email:
sys.exit("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)")
if not to_email_1:
sys.exit("Set TO_EMAIL_1")
if not to_email_2:
sys.exit("Set TO_EMAIL_2")
# Each personalization can carry its own headers, which override the
# top-level `headers` for that recipient.
response = mailchannels.Emails.send(
{
"from": {"email": from_email, "name": "Your Name"},
"personalizations": [
{
"to": [{"email": to_email_1}],
"headers": {"X-Campaign-Id": "welcome-2026-cohort-a"},
},
{
"to": [{"email": to_email_2}],
"headers": {"X-Campaign-Id": "welcome-2026-cohort-b"},
},
],
"subject": "Hello from MailChannels",
"text": "Hello from MailChannels.",
}
)
print(response)
<?php
require_once __DIR__ . '/vendor/autoload.php';
use MailChannels\Client;
$api_key = getenv('MAILCHANNELS_API_KEY') or exit("Error: MAILCHANNELS_API_KEY is not set\n");
$from_email = getenv('FROM_EMAIL') or exit("Error: FROM_EMAIL is not set\n");
$to_email_1 = getenv('TO_EMAIL_1') or exit("Error: TO_EMAIL_1 is not set\n");
$to_email_2 = getenv('TO_EMAIL_2') or exit("Error: TO_EMAIL_2 is not set\n");
$client = new Client(apiKey: $api_key);
// Each personalization can carry its own headers, which override the
// top-level `headers` for that recipient.
$response = $client->emails->send([
'from' => ['email' => $from_email, 'name' => 'Your Name'],
'personalizations' => [
[
'to' => [['email' => $to_email_1]],
'headers' => ['X-Campaign-Id' => 'welcome-2026-cohort-a'],
],
[
'to' => [['email' => $to_email_2]],
'headers' => ['X-Campaign-Id' => 'welcome-2026-cohort-b'],
],
],
'subject' => 'Hello from MailChannels',
'text' => 'Hello from MailChannels.',
]);
print_r($response->toArray());
When a header is defined both globally and in a personalization object, the value in the personalization object is used.
Restricted headers
The following names cannot be used as keys in theheaders JSON object. This list is non-exhaustive.
- Authentication-Results
- BCC
- CC
- Content-Transfer-Encoding
- Content-Type
- DKIM-Signature
- From
- Message-ID
- Received
- Reply-To
- Subject
- To

