Types d'événements
Abonnez-vous à n’importe quelle combinaison de ces types d’événements lorsque vous créez un webhook.
| Événement | Se déclenche quand | Définit last_event à |
|---|---|---|
email.scheduled |
Un e-mail avec scheduled_at a été accepté. |
scheduled |
email.sent |
L’e-mail a été transmis à Amazon SES. | sent |
email.delivered |
Le serveur de messagerie du destinataire a accepté l’e-mail. | delivered |
email.delivery_delayed |
La distribution est retardée ou échoue temporairement ; SES continue de réessayer. | delivery_delayed |
email.bounced |
Échec permanent (l’adresse n’existe pas, le domaine rejette). | bounced |
email.complained |
Le destinataire a signalé l’e-mail comme spam. | complained |
email.opened |
Le destinataire a ouvert l’e-mail (nécessite le suivi des ouvertures). | opened |
email.clicked |
Le destinataire a cliqué sur un lien (nécessite le suivi des clics). | clicked |
email.failed |
SpacePost ou SES n’a pas pu envoyer l’e-mail (rejeté, échec de rendu, équipe ou tenant en pause). | failed |
email.suppressed |
Un destinataire a été ignoré car il figure dans votre liste de suppression. | suppressed |
Forme du payload
Section intitulée « Forme du payload »Les corps des webhooks sont exactement ceux de Resend : les gestionnaires écrits pour Resend continuent donc de fonctionner.
{ "type": "email.delivered", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "broadcast_id": "0192e1c4-0000-7000-8000-0000000000bb", "tenant_id": "0192e1c4-5555-7000-8000-0000000000cc", "tags": { "category": "welcome" } }}typeest l’événement ;created_atest le moment où l’événement s’est produit.data.email_id,from,to(tous les destinataires de l’e-mail, pas seulement celui concerné),subjectetcreated_at(date de création de l’e-mail) sont toujours présents.data.broadcast_idn’est présent que pour les e-mails de campagne.data.tenant_idn’est présent que si l’e-mail a été envoyé pour un tenant (mode plateforme). C’est notre id de tenant, pas votreexternal_id.data.tagsn’est présent que si l’e-mail avait des tags, sous forme d’objet ({ "name": "value" }).- Certains événements ajoutent un objet supplémentaire à
data, nommé d’après l’événement :bounce,click,open,failedousuppressed. Ils sont listés ci-dessous. Rien d’autre n’est ajouté : il n’y a pas de clésbounceType,delayTypeoureasonau niveau supérieur.
Exemples
Section intitulée « Exemples »email.scheduled
Section intitulée « email.scheduled »{ "type": "email.scheduled", "created_at": "2026-10-23T14:02:09.700Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Your trial ends tomorrow", "created_at": "2026-10-23T14:02:09.512Z" }}email.sent
Section intitulée « email.sent »{ "type": "email.sent", "created_at": "2026-10-23T14:02:10.100Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.delivered
Section intitulée « email.delivered »{ "type": "email.delivered", "created_at": "2026-10-23T14:02:11.350Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.delivery_delayed
Section intitulée « email.delivery_delayed »Déclenché pour les retards de distribution SES et pour les rebonds temporaires. Un simple retard n’ajoute aucun champ. Un rebond temporaire porte aussi l’objet bounce (voir plus bas, avec type: "Transient").
{ "type": "email.delivery_delayed", "created_at": "2026-10-23T14:07:00.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.bounced
Section intitulée « email.bounced »Seuls les rebonds définitifs atteignent cet événement, et ils ajoutent l’adresse à votre liste de suppression. data.bounce contient type (Permanent), subType et le message du serveur destinataire.
{ "type": "email.bounced", "created_at": "2026-10-23T14:02:12.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["nobody@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "bounce": { "type": "Permanent", "subType": "General", "message": "smtp; 550 5.1.1 The email account that you tried to reach does not exist." } }}Les sous-types de rebond incluent General, NoEmail, Suppressed, OnAccountSuppressionList, MailboxFull, MessageTooLarge, ContentRejected et AttachmentRejected.
email.complained
Section intitulée « email.complained »Aucun champ supplémentaire. L’adresse est ajoutée à votre liste de suppression.
{ "type": "email.complained", "created_at": "2026-10-23T15:30:00.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Our monthly newsletter", "created_at": "2026-10-23T14:02:09.512Z" }}email.opened
Section intitulée « email.opened »{ "type": "email.opened", "created_at": "2026-10-23T14:05:44.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "open": { "ipAddress": "203.0.113.7", "userAgent": "Mozilla/5.0 (Macintosh)" } }}email.clicked
Section intitulée « email.clicked »{ "type": "email.clicked", "created_at": "2026-10-23T14:06:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "click": { "link": "https://acme.com/get-started", "ipAddress": "203.0.113.7", "userAgent": "Mozilla/5.0 (Macintosh)", "timestamp": "2026-10-23T14:06:10.000Z" } }}email.failed
Section intitulée « email.failed »{ "type": "email.failed", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "failed": { "reason": "Attachment https://files.acme.com/report.pdf returned HTTP 404" } }}email.suppressed
Section intitulée « email.suppressed »suppressed.reason vaut suppression_list (le destinataire figure dans votre liste de suppression) ou recipient_domain_does_not_accept_mail (le domaine du destinataire n’a pas de serveur de messagerie).
{ "type": "email.suppressed", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com", "other@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "suppressed": { "recipients": ["other@example.com"], "reason": "suppression_list" } }}Typer les événements en TypeScript
Section intitulée « Typer les événements en TypeScript »Le SDK Node exporte une union WebhookPayload discriminée par type, et spacepost.webhooks.verify() la renvoie : en affinant sur event.type, vous obtenez les bons champs data :
import type { WebhookPayload } from "@spacepost/node";
function handle(event: WebhookPayload) { switch (event.type) { case "email.bounced": return event.data.bounce?.subType; case "email.clicked": return event.data.click?.link; case "email.suppressed": return event.data.suppressed.recipients; case "email.failed": return event.data.failed.reason; default: return event.data.tenant_id; // present when the email was sent for a tenant }}