send() does not wait for your email to land. It’s a fast, durable enqueue: the
call returns as soon as SenderKit has accepted and recorded the message, and delivery
happens in the background. Understanding that split — accept now, deliver later — is
the key to using SenderKit correctly.
Synchronous accept, asynchronous delivery
A send returns202 almost immediately with a message id, a status of
"queued" (or "scheduled" if you passed a future scheduledAt), and livemode.
That response means accepted, not delivered. SenderKit then renders the
template, dispatches to a provider, and updates
the message as the provider reports back.
GET /v1/messages or tail the live stream.
Scheduling sends
Pass a futurescheduledAt (ISO 8601 string with offset, or a Date) to defer
delivery. The send is accepted immediately with status: "scheduled"; SenderKit
holds the message until the fire time, then dispatches it through the normal
pipeline.
scheduledAt must be in the future (with a few seconds of clock-skew
tolerance) and no more than 30 days out. Omit it to send immediately.
Template sends and raw sends
Most sends reference a stored template by slug. You can also send raw content inline — supply achannel and content instead of a template — for one-off
messages that don’t warrant a template. Raw content is interpolated with your vars
only when you opt in; otherwise it’s delivered verbatim. (A send specifies a
template or content, never both.)
Idempotency
Because the network is unreliable and the SDK retries transient failures, the same send can hit the API more than once. An idempotency key makes that safe: a repeat key within your workspace returns the original message instead of creating a duplicate. The SDK attaches anIdempotency-Key header automatically (it generates one if you
don’t pass idempotencyKey), so retries don’t double-send out of the box. Pass your
own key when the natural unit of work is something you can name:
Email deliverability
SenderKit applies two automatic behaviors to every email send (template and raw) that improve inbox placement and comply with bulk-sender requirements: Multipart delivery (HTML + plain text) Every email ships asmultipart/alternative: an auto-generated plain-text body
is derived from the final HTML at send time (after template variables and
reusable blocks are applied). HTML-only mail scores worse with spam filters; the
auto-generated part keeps the plain-text copy in sync with the HTML without
requiring you to maintain it manually.
For raw sends (sendRaw / senderkit_send_raw), you can supply your own text
field to override the auto-generated version.
List-Unsubscribe headers (RFC 8058)
All non-system email sends include List-Unsubscribe and
List-Unsubscribe-Post: List-Unsubscribe=One-Click headers, required by Gmail
and Yahoo for bulk senders. When a recipient uses the one-click unsubscribe
link, SenderKit records the opt-out and skips future sends from your workspace
to that address — the skipped messages are recorded with status opted_out.
Opt-out suppression is workspace-scoped: an opt-out in workspace A does not
block sends in workspace B. It applies to all email from your workspace,
not per-template.
Ordering and batching
Delivery is concurrent and out of band, so send order is not delivery order — don’t depend on two sends arriving in sequence. To send many messages at once, the SDK’ssendBatch fans out with bounded concurrency; each item becomes its own
message with its own idempotency key.
Messages
Track a send from queued to delivered.
TypeScript SDK
send, sendRaw, and sendBatch in detail.