Radondocs

Batch sending

Send many distinct emails in one call with sendBatch — native bulk endpoints where the provider has one, graceful sequential fallback everywhere else.

Pro email.sendBatch() sends an array of distinct messages in one call and returns one result per message, in order. It's a Pro feature — it needs a verified license even on a free provider, so call await email.init() first.

Send a batch
const batch = await email.sendBatch([
  { to: "ada@example.com",   subject: "Hi Ada",   text: "…" },
  { to: "grace@example.com", subject: "Hi Grace", text: "…" },
]);

batch.results.length; // 2 — one SendResult per input, same order
batch.batched;        // true if a native bulk endpoint was used, false if sequential

Each message is fully prepared first — managed templates and free {{variable}} interpolation are applied per message before sending, exactly like send().

Native vs. sequential

Not every provider has a bulk endpoint. sendBatch() handles both transparently:

  • If the provider advertises capabilities.batch, Radon calls its native bulk endpoint — one HTTP request for the whole array.
  • Otherwise Radon falls back to sequential per-message sends, preserving order. Same result shape, same SendResult objects — just more round trips.

The batched flag on the result tells you which path ran:

const batch = await email.sendBatch(messages);
if (!batch.batched) {
  // Sent one-by-one — the provider has no bulk API.
}

The fallback is automatic, never silent

You never get a UnsupportedOperationError from sendBatch() for a provider that lacks a bulk endpoint — the facade sends sequentially instead. batched: false is how you know, not an exception.

Per-provider caps

Only three providers have a native bulk endpoint today; the rest fall back to sequential.

ProviderNative batchPer-request cap
ResendYes (/emails/batch)100 messages
PostmarkYes (/email/batch)500 messages
MailjetYes (Messages array)Per Mailjet's own limits
Everything elseNo — sequential fallback

Respect the native cap

Radon sends your array in a single request to a native-batch provider — it does not auto-chunk. Passing more than Resend's 100 or Postmark's 500 in one sendBatch() call will be rejected by the provider. Split large lists into chunks yourself.

Choosing a provider for the batch

Like send(), sendBatch() uses the default provider unless you name one:

await email.sendBatch(messages, { provider: "postmark" });

Partial failures

With native batch, providers report per-message outcomes in each SendResult. Postmark, for example, can return a per-row error inside an otherwise-200 batch — Radon surfaces the failed rows via accepted / rejected and preserves the provider's raw response on result.raw for inspection.

for (const r of batch.results) {
  if (r.rejected?.length) {
    console.warn("rejected:", r.rejected, r.raw);
  }
}

Full signature

email.sendBatch(messages: EmailMessage[], options?: { provider?: string }): Promise<BatchResult>Pro

Send many messages. Uses the provider's native bulk endpoint when available (capabilities.batch), else sends sequentially. Requires a verified license. Fires the onSent hook once per resulting message.

resultsSendResult[]

One SendResult per input message, in the same order.

batchedboolean

true if a native bulk endpoint sent them in one request; false if Radon fell back to sequential sends.

Next steps

On this page