Build bulk email sending without one giant request: select eligible recipients, snapshot intent, batch safely, handle partial results, suppress quickly, and measure outcomes.
A bulk email API submits many individually addressed messages through a provider using a batch endpoint or a controlled series of requests. It can reduce request overhead and centralize templates, but it does not replace recipient eligibility, personalization, queueing, rate control, idempotency, suppression, or delivery-event processing.
The safe unit is still one recipient message with one eligibility decision and one observable outcome. A batch is a transport optimization around those records—not one email exposing a list in To or Cc, and not permission to upload every address your company has collected.
Bulk API, single-send API, SMTP, and campaigns
SURFACE BEST FIT APPLICATION OWNS
Single-send API receipts, alerts, auth, low fan-out event, recipient, retry intent
Bulk API many similar personalized messages selection, batching, partial results
SMTP submission existing mail libraries and MTAs envelope, MIME, retries, message IDs
Campaign system newsletters and marketing sends audience rules, content, scheduling
Automation lifecycle journeys entry, delays, branches, exits
A provider may expose several surfaces. Use the one whose state model matches the job.Reference architecture for bulk email
AUDIENCE QUERY
resolve consent + status + frequency + suppression at cutoff
|
v
SEND SNAPSHOT
immutable campaign/version + recipient intents + personalized variables
|
v
BATCH PLANNER
claim bounded rows -> enforce provider/account/domain rate budgets
|
v
PROVIDER API
template/default content + per-recipient destination/replacements/tags
|
v
RESULT RECONCILIATION
accepted/rejected/ambiguous per recipient -> retry only eligible work
|
v
DELIVERY EVENTS
delivered/bounced/complained/unsubscribed -> ledger + suppressionAmazon SES's SendBulkEmail API illustrates the common shape: default template content plus an array of bulk entries with individual destinations, replacement template data, headers, and tags. Providers impose different batch sizes, quotas, rate limits, error models, and personalization behavior, so read the chosen endpoint contract rather than building around an assumed universal maximum.
Resolve eligibility before batching
- Identify the exact message purpose, list or program, jurisdictional policy, and audience cutoff time.
- Require an active address with the appropriate consent or relationship for that message.
- Exclude permanent bounces, complaints, unsubscribes, internal blocks, and known invalid addresses.
- Apply frequency, quiet-hour, plan, lifecycle, geography, and account-state rules before rendering.
- Deduplicate by normalized destination and message purpose while preserving the reason a person qualified.
- Re-check hard suppression immediately before submission because the snapshot can become stale.
Google's sender guidance says subscription mail should go to people who want it and requires eligible bulk marketing and subscribed messages to support one-click unsubscribe. Authentication, DMARC alignment, TLS, DNS, spam-rate, and message-format requirements apply to the sender—not only to the API provider.
Create an immutable send snapshot
send_id stable send/campaign version
recipient_intent_id unique(send_id, contact_id, destination)
contact_id internal identity
to_address normalized destination at cutoff
eligibility_reason consent/source/account rule that qualified
template_version immutable rendered-content version
locale resolved locale
variables_hash evidence of personalized input
status pending | claimed | accepted | failed | suppressed
provider_message_id recipient-level trace ID when available
attempt_count transport attempts, not billing/business attemptsDo not repeatedly run a changing segment query while a large send is in progress unless that behavior is explicitly designed. A snapshot makes counts, exclusions, content versions, support investigation, and retry behavior explainable. Continue applying urgent suppressions even after snapshot creation.
Personalize without leaking recipients
{
"template": "product-update-v7",
"defaults": { "releaseName": "Northstar 4.2" },
"entries": [
{
"to": "[email protected]",
"variables": { "firstName": "Sam", "workspace": "Acme" },
"metadata": { "recipientIntentId": "ri_2048" }
},
{
"to": "[email protected]",
"variables": { "firstName": "Lee", "workspace": "Orbit" },
"metadata": { "recipientIntentId": "ri_2049" }
}
]
}Each recipient should receive an individually addressed message. Never place the audience in To or Cc, and do not rely on Bcc as a bulk architecture: it limits recipient-level personalization and observability, increases privacy risk, and makes suppression and retries harder to explain.
Escape user-controlled variables for the output context, define behavior for missing values, and reject unexpected types before submission. Preview representative and worst-case rows. A default such as ‘there’ is safer than exposing a raw database identifier or sending broken braces.
Choose batch size from constraints
The provider's maximum is only one constraint. Choose a smaller operating batch when it improves queue fairness, timeout risk, memory use, cancellation latency, recipient-domain pacing, or partial-result handling. Large batches reduce HTTP overhead; small batches limit the ambiguity and blast radius of each request.
provider maximum entries per request
account requests and recipients per second
message size after template expansion
recipient-domain throttling and historical deferrals
worker concurrency and memory budget
request timeout and provider latency distribution
maximum acceptable cancellation delay
partial-response and idempotency capabilities
normal traffic that must share the same account or IP poolHandle rate limits and backpressure
- Use a durable queue; an HTTP request from an admin screen should schedule the send, not transmit the audience.
- Claim bounded work with leases so crashed workers release recipients safely.
- Enforce global, provider-account, IP-pool, mail-stream, and recipient-domain budgets where applicable.
- Honor provider retry guidance and apply jittered backoff to transient failures.
- Reserve capacity for password resets, receipts, and alerts instead of letting a newsletter occupy every worker.
- Expose pause, resume, and cancel controls that stop unclaimed work without erasing evidence.
Reconcile partial and ambiguous results
RESULT ACTION
Accepted + message ID Store ID; await delivery events
Rejected, permanent Mark failed/suppressed as policy requires
Rejected, retryable Schedule only that recipient with backoff
Mixed response Apply each entry result independently
Timeout before request Safe to retry only with known non-submission evidence
Timeout after submit Ambiguous: reconcile by idempotency key/provider evidence
Malformed response Preserve request ID; quarantine before broad retryAPI acceptance means the provider accepted responsibility for processing, not that the recipient server accepted the message or that it reached the inbox. Capture recipient-level provider IDs and process asynchronous delivery, bounce, complaint, and unsubscribe events idempotently.
Implement one-click unsubscribe and suppression
For eligible marketing and subscribed messages, implement the RFC 8058 header pair, a visible body link, a safe POST endpoint, and prompt suppression. The token must identify the subscription choice without requiring a login and without allowing unrelated account actions. DKIM must cover the one-click fields as required by the RFC.
An unsubscribe can arrive while batches are queued. Update the suppression record, cancel unclaimed recipient intents, and perform a final suppression check at send time. Keep suppression evidence even if the visible contact is deleted so an import cannot silently re-enable mail.
Separate bulk and transactional streams
Promotional bulk traffic and critical product messages have different urgency, cadence, consent, complaint exposure, and retry budgets. Use separate queues, rate limits, monitoring, and—when the infrastructure supports it—sending subdomains or streams. Separation reduces coupling but does not excuse either stream from authentication and responsible sending.
Bulk email API production checklist
- Snapshot a named audience and immutable template version with eligibility evidence.
- Store one intent per recipient and preserve recipient-level status through every batch.
- Personalize and address messages individually; never expose the audience in headers.
- Set batch size and concurrency below the provider maximum when operational constraints require it.
- Treat partial results and post-submit timeouts explicitly; do not retry an entire batch blindly.
- Re-check suppression at submission and stop queued work quickly after unsubscribe or complaint.
- Authenticate sending domains and monitor provider, mailbox, complaint, bounce, and domain signals.
- Keep critical transactional capacity isolated from bulk campaign pressure.
- Test pause, cancel, retry, duplicate event, stale segment, template failure, and rollback paths.
Frequently asked questions
What is a bulk email API?
It is an API surface that accepts multiple recipient messages in one request or supports efficient high-volume submission. A robust implementation still keeps recipient-level eligibility, personalization, idempotency, status, suppression, and delivery evidence.
Is a bulk email API the same as a campaign platform?
No. The API is transport. A campaign platform normally adds audience management, consent, segmentation, content editing, scheduling, experimentation, unsubscribe handling, analytics, and operational controls. Building directly on an API means your application owns those layers.
How many recipients should be in one batch?
Stay within the provider's documented maximum, then choose a smaller size if needed for timeouts, memory, cancellation latency, rate budgets, or partial failures. Benchmark the real template and account limits; no universal batch size is optimal.