Lifecycle hooks
Observe sender activity without putting message bodies in hook context.
Hooks observe sends for metrics and tracing without coupling your application to a provider. Their contexts include delivery metadata, not a message body.
The one rule
import { createMailer } from "sently/mailer";
import { ResendTransport } from "sently/transports/resend";
const mailer = await createMailer({
transport: new ResendTransport({
apiKey: process.env.RESEND_API_KEY!,
}),
hooks: {
onSuccess: ({ provider, subject, to }, result, durationMs) => {
console.log(provider, subject, result.messageId, durationMs);
console.log(to);
},
},
});await mailer.send({
from: "hello@example.com",
to: "person@example.com",
subject: "Welcome",
text: "Thanks for joining.",
});Hook callbacks
| Channel | Callbacks | Context |
|---|---|---|
onSend, onSuccess, onError, onRetry, onFallback | messageId, recipients, subject, provider. | |
| SMS | onSend, onSuccess, onError, onRetry, onFallback | messageId, recipient number, provider. |
onSend, onSuccess, onError, onRetry, onFallback | messageId, recipient number, provider. | |
| Push | onSend, onSuccess, onError, onRetry, onFallback | messageId, redacted endpoint / FCM token fingerprint, provider. |
onSuccess receives the delivery result and optional duration in milliseconds. onError receives the error and optional duration.
Retry and fallback
onRetry runs only with RetryTransport. onFallback runs only with a fallback (or weighted fallback) transport.
Wire either decorator around the channel transport you pass to createMailer, createSmsSender, createWhatsAppSender, or createPushSender.
Troubleshooting
onRetry is wired only when the sender's transport is RetryTransport.
Hook failures are intentionally swallowed so observability code cannot break message delivery.
The endpoint path can contain a long-lived delivery token and is not exposed in full to hooks.