Send Batch Emails
Send up to 100 emails in a single API call. The attachments field is not supported in batch mode.
/emails/batchResend Compatibility: Compatible
Body Parameters
The request body is an array of email objects (max 100).
fromstringrequiredSender email address. To include a friendly name, use the format "Your Name <sender@domain.com>".
tostring | string[]requiredRecipient email address. For multiple addresses, send as an array of strings. Max 50.
subjectstringrequiredEmail subject.
htmlstringThe HTML version of the message.
textstringThe plain text version of the message.
bccstring | string[]BCC recipient email address(es).
ccstring | string[]CC recipient email address(es).
reply_tostring | string[]Reply-to email address(es).
headersobjectCustom headers to add to the email.
scheduled_atstringSchedule the email to be sent later. ISO 8601 (2026-08-05T11:52:01.858Z) or natural language (in 1 min), up to 30 days ahead. A scheduled email is created but not sent until its time arrives, and can be cancelled until then.
tagsarrayCustom data passed in key/value pairs.
namestringrequiredThe name of the email tag. Max 256 characters.
valuestringrequiredThe value of the email tag. Max 256 characters.
Headers
Idempotency-KeystringheaderAdd an idempotency key to prevent duplicated batch sends. Max 256 characters. Expires after 24 hours.
x-batch-validationstringheaderHow per-item failures are reported: strict (default) or permissive.
In strict mode the batch is sent only if every email in it is valid — one bad item rejects the whole call and nothing is created. In permissive mode the valid emails are created and sent, and the rejected ones come back in the response's errors array.
One difference from Resend: a request body that fails schema validation — a missing from, a malformed address — is still rejected as a whole in permissive mode, with a 400 rather than an errors entry. Permissive reporting covers the per-item checks that run after the body parses: template resolution, topic lookup, sending-domain verification and content safety.
Response Fields
dataarrayArray of objects containing the id of each created email. Failed emails have an empty id and an error field.
errorsarrayPresent only when x-batch-validation: permissive was sent, and present then even when empty. Each entry is { "index", "message" }, where index is the 0-based position of the rejected email in the request. When it is non-empty, data is no longer index-aligned with the request — the rejected items have no slot in it.
curl -X POST 'https://api.postflare.app/emails/batch' \
-H 'Authorization: Bearer re_xxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '[
{
"from": "Acme <hello@acme.com>",
"to": ["user1@example.com"],
"subject": "Hello User 1",
"html": "<p>Hello User 1!</p>"
},
{
"from": "Acme <hello@acme.com>",
"to": ["user2@example.com"],
"subject": "Hello User 2",
"html": "<p>Hello User 2!</p>"
}
]'import { Resend } from 'resend';
const resend = new Resend('re_xxxxxxxxx');
const { data, error } = await resend.batch.send([
{
from: 'Acme <hello@acme.com>',
to: ['user1@example.com'],
subject: 'Hello User 1',
html: '<p>Hello User 1!</p>',
},
{
from: 'Acme <hello@acme.com>',
to: ['user2@example.com'],
subject: 'Hello User 2',
html: '<p>Hello User 2!</p>',
},
]);Response
{
"data": [
{ "id": "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794" },
{ "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012" }
]
}