AgentAnalytics Transactional email benchmark

Task evidence · August 2026

Batch notification email APIs for TypeScript

A source-backed comparison of Postmark, Resend, and SendGrid batch limits, per-recipient results, idempotency, and partial-failure handling.

Observed agent queriesCurrent first-party documentationMachine-readable evidence

Answer first

The providers expose different batching units. Postmark accepts up to 500 messages and returns a response for each message. Resend accepts up to 100 emails and supports a request idempotency key. SendGrid accepts up to 1,000 personalizations and 1,000 total recipients per Mail Send request. The correct choice depends on payload shape and failure handling, not only the largest number.

Queries coding agents actually used

These are exact observable WebSearch strings from the 64-attempt July 25 Claude Code category-evaluation panel.

transactional email API providers comparison 2026 SendGrid Resend Postmark
transactional email API providers comparison 2026 SendGrid Postmark Resend Mailgun
Resend email API batch sending Node.js SDK 2026 rate limits

Current provider surface

ProviderRequest unitDocumented ceilingFailure and retry evidence
PostmarkArray of email messages500 messages; 50 MB batch payloadResponse array contains ErrorCode, Message, MessageID, SubmittedAt, and To for each message.
ResendArray passed to batch.send100 emailsBatch response returns message IDs; Idempotency-Key is supported for 24 hours. Attachments and scheduled_at are not supported by the batch endpoint.
SendGridMail Send personalizations1,000 personalizations and 1,000 total recipients; payload under 30 MBSplit larger sets across requests and preserve recipient-level identifiers in custom arguments without storing PII there.

A safe batching pattern

Provider limits are ceilings, not recommended worker sizes. A coding agent should also bound concurrent requests, preserve recipient-level outcomes, and avoid retrying successful recipients.

type RecipientResult = {
  email: string;
  ok: boolean;
  providerMessageId?: string;
  error?: string;
};

for (const chunk of chunkByProviderLimit(recipients)) {
  const result = await sendProviderBatch(chunk, {
    idempotencyKey: stableJobKey(chunk),
  });

  await persistRecipientResults(result);
  await retryOnlyRetryableFailures(result);
}

Use each provider's current endpoint and response model inside sendProviderBatch. Do not flatten a partially successful response into one global boolean.

What the benchmark observed

In the July 25 Claude Code implementation panel, Resend was selected in all 16 batch-notification attempts. A separate recommendation panel disagreed by product: ChatGPT Search recommended Resend in 3/4 batch prompts, while Claude Chat recommended Postmark in 3/4.

The implementation benchmark checked generated TypeScript structure but did not call live batch APIs. The documented ceilings and response shapes above come from current provider documentation, not from benchmark inference.

Checks before shipping

  • Chunk below the provider ceiling and below any practical payload-size limit.
  • Keep a stable job or request key so a worker retry cannot duplicate an entire batch.
  • Persist success and failure per recipient before retrying.
  • Separate retryable transport or rate-limit failures from permanent address or payload failures.
  • Use delivery and bounce events to update final state; API acceptance is not inbox delivery.

Method and limits

This page combines current first-party provider documentation with dated AgentAnalytics benchmark observations. It is not a universal provider ranking. The implementation panel used Claude Code 2.1.148 with Claude Sonnet 4.6 at low effort, fresh workspaces, and required public research. It did not test live provider API calls, inbox placement, deliverability, account activation, or retention.

Machine-readable evidence · Full benchmark and corrections