The message lifecycle
The status enum also includes
dispatched. In the current pipeline a message moves
queued → rendered → sent, and the moment a provider accepts it is recorded as a
dispatched event on the message’s timeline while the status itself becomes
sent. Read sent as “handed to the provider.”opted_out reflects only a send skipped before dispatch because the
recipient had already opted out. If a recipient unsubscribes or complains
after a message reached a terminal outcome (delivered or failed), that
outcome is unchanged — the unsubscribe/complaint is recorded and reported via
webhook events, but it no longer overwrites a delivery
result that already happened.rendered → sent → delivered) without calling a provider, so your logs look the same
as live without anything leaving the building.
Querying messages
List messages newest-first with cursor pagination, and filter bystatus, channel,
template, or your own metadata:
Engagement (opens & clicks)
For email, SenderKit also records provider-reported opens and link clicks asopenedAt / clickedAt on the message — each set once, on the
first occurrence. These are engagement signals, not lifecycle states: they
never change a message’s status, and delivered remains the terminal
happy-path status regardless of whether the recipient later opens it or clicks
a link.
Subscribe to the message.opened / message.clicked webhook events
to be notified as they happen, or read the fields directly via
messages.get/messages.list.
Retention
Messages are retained for a limited window and then deleted:Sending
How a message gets created and dispatched.
Channels & Providers
Who delivered the message and how failures surface.