Événements e-mail
Nous émettons des événements à mesure que chaque destinataire progresse dans la livraison. Un envoi à trois adresses produit trois flux indépendants, corrélés par email_id et recipient_id. Cette page définit les types d'événements e-mail. Consultez Webhooks pour les signatures, les réessais, l'ordre et le rejeu.
Chaque destinataire commence à email.accepted, puis email.processed. Un destinataire de broadcast est son propre message, il reçoit donc aussi son propre email.accepted, mais uniquement dans les événements API et le journal e-mail plutôt que via un webhook. À partir de là, le message est accepté par le serveur de réception (email.delivered), est différé et réessayé (email.deferred, qui se résout en livré ou rebondi), est refusé par le serveur de réception (email.bounced), ou ne fait l'objet d'aucune tentative de livraison (email.rejected). Après une livraison, le flux peut se poursuivre avec email.out_of_band_bounce, email.complained, email.opened, email.clicked, email.unsubscribed et email.list_unsubscribed.
Chaque destinataire aboutit à exactement un statut terminal, delivered, bounced, complained ou rejected, renvoyé comme status par destinataire depuis GET /v1/email/messages/{message_id}/recipients. Les événements d'engagement ne le modifient jamais : un destinataire qui a ouvert reste delivered. Un rapport de rebond tardif le modifie, car le serveur de réception rétracte une acceptation déjà donnée, et le destinataire passe de delivered à bounced. Le message dans son ensemble a son propre statut agrégé et ses compteurs par état sur GET /v1/email/messages/{message_id}.
L'enveloppe d'événement
Les événements arrivent sous forme d'enveloppe à trois champs commune à tous les webhooks : type, timestamp (quand l'événement s'est produit, RFC 3339) et un objet data propre au type.
Exemple de code
{
"type": "email.delivered",
"timestamp": "2026-07-23T14:51:47.107Z",
"data": {
"email_id": "em_01ky7qc398fmxraqtxn604zeq9",
"recipient_id": "er_01ky7qc398fmwsc96nt6anrbqs",
"workspace_id": "ws_01ky7m21hjffh9s8kq76gyb1xf",
"recipient": "delivered@messagebird.dev",
"recipient_role": "to",
"tags": [{ "name": "category", "value": "welcome" }],
"metadata": { "order_id": "ord_123" },
"broadcast_id": null
}
}Chaque événement sortant inclut email_id, recipient_id, workspace_id, l'adresse recipient et son enveloppe recipient_role (to, cc ou bcc). Il reprend aussi tags et metadata de la requête d'envoi pour que vous puissiez corréler l'événement avec vos enregistrements. Chaque valeur optionnelle est null quand l'envoi n'en avait pas, y compris broadcast_id : il nomme le broadcast dont l'envoi faisait partie, pour que vous puissiez regrouper les événements d'un broadcast sans rechercher chaque envoi, et il est null sur un envoi sans broadcast associé. Un cas renvoie null pour un envoi qui en avait un : un lien de désinscription issu d'un e-mail envoyé avant l'ajout du champ ne nomme aucun broadcast, donc un opt-out via un tel lien renvoie null sur email.unsubscribed et email.list_unsubscribed, que l'e-mail ait été envoyé par un broadcast ou non. Traitez null sur ces deux événements comme non concluant, sinon vous sous-comptez les opt-outs d'un broadcast. broadcast_id vous parvient uniquement via le webhook : les événements API ci-dessous renvoient chaque événement sans ce champ. Les types d'événements ajoutent des champs décrits dans les sections cycle de vie, engagement, suppression et entrant.
Les mêmes événements sont interrogeables après coup depuis GET /v1/email/messages/{message_id}/events, où chacun dispose aussi d'un id (préfixe ev_) et d'un occurred_at. Utilisez-le pour rattraper, rejouer ou réconcilier avec ce que votre endpoint a reçu. Quelques champs ne vous parviennent que via ce API plutôt que via le webhook ; la description de l'événement concerné les identifie.
Événements de cycle de vie
email.accepted
Nous avons accepté l'envoi et commencé à préparer la livraison. Se déclenche une fois par destinataire demandé et constitue le premier événement de ce flux. Un destinataire de broadcast en reçoit un aussi, car chaque destinataire est son propre message, mais il est enregistré plutôt que livré : lisez-le depuis les événements API ou le journal e-mail, pas depuis votre endpoint webhook. Payload : la base d'identité uniquement.
email.processed
Le message est construit et mis en file d'attente pour livraison au serveur de messagerie du destinataire. Payload : la base d'identité uniquement via le webhook ; les événements API ajoutent mailbox_provider et mailbox_provider_region, la classification du système de messagerie de réception (par exemple gmail, NA), présente quand elle a pu être déterminée et null sinon. Comparer le timestamp de cet événement avec celui de email.accepted vous donne notre propre temps de traitement sur un envoi unitaire. Un broadcast n'a pas un tel intervalle : son acceptation et son traitement portent le même instant d'expédition, les deux horodatages coïncident donc au lieu d'encadrer un traitement, et l'acceptation ne vous parvient que via les événements API, en tant que occurred_at.
email.delivered
Le serveur de messagerie de réception a accepté le message et en a pris la responsabilité. Cet événement n'établit ni le placement en boîte de réception ni la lecture. Inbox Insights fournit des estimations de placement par échantillonnage ; les événements d'ouverture et de clic enregistrent les requêtes de suivi. Payload : la base d'identité uniquement via le webhook ; les événements API ajoutent sending_ip, l'adresse depuis laquelle le message a été envoyé, utile quand un problème de délivrabilité cible une IP, plus mailbox_provider et mailbox_provider_region.
email.deferred
Un échec temporaire : le serveur de réception nous a demandé de réessayer plus tard (boîte pleine, greylisting, limitation du débit). Nous réessayons automatiquement, et le destinataire finit par se résoudre en email.delivered ou email.bounced, cet événement est donc informatif et non terminal, et un destinataire peut être différé plusieurs fois d'abord. Payload : bounce_type, bounce_class, defer_reason (la raison donnée par le serveur) et sending_ip via le webhook ; les événements API ajoutent mailbox_provider et mailbox_provider_region.
Événements d'échec
email.bounced
Un échec permanent au moment de SMTP : le serveur de réception a refusé le message, et le statut terminal du destinataire devient bounced. Payload : bounce_type (voir le tableau de classification), bounce_class, bounce_code (le code de réponse SMTP, par exemple 550), bounce_description (la raison donnée par le serveur) et sending_ip via le webhook ; les événements API ajoutent mailbox_provider et mailbox_provider_region. Un rebond dur supprime l'adresse.
email.out_of_band_bounce
Un rebond tardif : le serveur de réception a accepté le message au moment de SMTP puis a envoyé un rapport de rebond après coup. Il a la même classification que email.bounced (bounce_type, bounce_class, bounce_code, bounce_description, sending_ip via le webhook ; mailbox_provider et mailbox_provider_region depuis les événements API). Quand le rapport est classé comme rebond (toute classe du tableau), le serveur a rétracté son acceptation précédente, et le destinataire passe de delivered à bounced. Les rapports dont la classe n'est pas dans le tableau, comme les réponses automatiques, sont enregistrés dans la chronologie et ne modifient pas le statut. Un rebond tardif dur supprime aussi l'adresse.
email.rejected
Le destinataire n'a jamais atteint le serveur de messagerie distant, aucune tentative de livraison n'a donc eu lieu. C'est ce qui distingue un rejet d'un rebond, où c'est le serveur de réception qui refuse. Payload : rejection_reason, également sur l'enregistrement du destinataire, l'une des valeurs suivantes :
| rejection_reason | Signification |
|---|---|
| recipient_suppressed | Le destinataire est bloqué au niveau de l'espace de travail, par la liste de suppression ou par une préférence déclarée, la livraison n'a donc jamais été tentée |
| transmission_failed | Le message n'a pas pu être transmis pour livraison |
| generation_failure | Le message n'a pas pu être construit pour la livraison, un problème de template ou de contenu |
| policy_rejection | La politique d'envoi a refusé le message |
| domain_unverified | Le domaine d'envoi n'était pas vérifié |
| quota_exceeded | Le quota d'envoi de l'organisation a été atteint |
| recipient_not_allowed | Le destinataire n'était pas autorisé pour cet envoi ; les envois sur un domaine d'onboarding partagé n'atteignent que les membres vérifiés de votre espace de travail |
Les événements API ajoutent aussi mailbox_provider et mailbox_provider_region quand le système de messagerie de réception a pu être classé avant le rejet.
email.complained
Le destinataire a marqué le message comme spam et le fournisseur de messagerie l'a signalé via sa boucle de rétroaction. Les plaintes arrivent après la livraison et fixent le statut terminal à complained. Payload : feedback_type, le type de rapport envoyé par le fournisseur, par exemple abuse ou fraud, et null quand le fournisseur ne l'a pas précisé, plus mailbox_provider et mailbox_provider_region depuis les événements API. Une plainte supprime l'adresse pour le courrier marketing. Maintenez votre taux de plaintes bas : les fournisseurs limitent les expéditeurs qui accumulent des signalements.
Événements d'engagement
email.opened
Le pixel de suivi dans le corps du message a été chargé. Payload : ip_address et user_agent quand ils sont connus ; les événements API ajoutent is_prefetched, country (ISO 3166-1 alpha-2, dérivé de l'IP du client), mailbox_provider et mailbox_provider_region. Vérifiez is_prefetched avant de comptabiliser une ouverture. Il est true quand une fonctionnalité de confidentialité de la boîte de réception a chargé le pixel automatiquement plutôt qu'une personne ouvrant le message, et les comptabiliser gonfle votre taux d'ouverture. Suivi des ouvertures et des clics couvre l'instrumentation.
email.clicked
Le destinataire a cliqué sur un lien suivi. Payload : url (le lien cliqué), ip_address et user_agent quand ils sont connus ; les événements API ajoutent country, mailbox_provider et mailbox_provider_region. Les clics sont généralement un signal d'engagement plus fort que les ouvertures, car les proxys de confidentialité peuvent charger les pixels de suivi automatiquement.
email.unsubscribed
Le destinataire a utilisé le lien de désinscription dans le corps du message. Payload : la base d'identité uniquement via le webhook ; les événements API ajoutent mailbox_provider et mailbox_provider_region. Enregistre une préférence d'opt-out qui bloque le courrier marketing. Liens de désinscription explique comment le lien est intégré à votre e-mail.
email.list_unsubscribed
Le destinataire a utilisé le bouton de désinscription en un clic que le fournisseur de messagerie affiche dans sa propre interface, piloté par les en-têtes List-Unsubscribe du message. Payload : la base d'identité uniquement via le webhook (plus mailbox_provider et mailbox_provider_region depuis les événements API) ; le mécanisme est le type d'événement lui-même, c'est pourquoi il est séparé de email.unsubscribed. Enregistre aussi une préférence d'opt-out qui bloque le courrier marketing.
Événements au niveau message
Deux événements décrivent le message dans son ensemble plutôt qu'un seul destinataire, leur data contient donc email_id, workspace_id, tags et metadata mais aucune identité de destinataire. Tous deux appartiennent à l'envoi programmé.
email.scheduled
Nous avons accepté un envoi avec un scheduled_at dans le futur. Payload : la base au niveau message plus scheduled_at. Quand ce moment arrive, le cycle de vie par destinataire commence à email.accepted.
email.canceled
Un message programmé a été annulé avant son envoi, il ne produit donc aucun événement de cycle de vie par destinataire. Payload : la base au niveau message uniquement.
Événements entrants et de boîte aux lettres
email.received couvre le courrier entrant. Il se déclenche quand nous recevons et analysons un message entrant. Son payload inclut le inbound_message_id, l'adressage, le sujet et les verdicts d'authentification. La configuration, le payload et le API de récupération sont dans Réception d'e-mail. Une boîte aux lettres a sa propre famille email_mailbox.* en plus, couverte dans le guide des boîtes aux lettres.
Classification des rebonds
bounce_class est la classification numérique des rebonds incluse sur email.bounced, email.out_of_band_bounce et email.deferred. Elle se regroupe dans le bounce_type grossier et conserve le code fin, pour que vous puissiez distinguer une boîte pleine d'un échec de routage même si les deux signalent soft :
| bounce_class | bounce_type | Signification |
|---|---|---|
| 1 | undetermined | La réponse du serveur de réception était ambiguë |
| 10, 30 | hard | Échec permanent : adresse invalide ou domaine inexistant |
| 20 to 24, 40, 70, 100 | soft | Échec transitoire : boîte pleine, serveur temporairement indisponible, problème DNS ou de routage |
| 25 | admin | Refus administratif : relais refusé, domaine sur liste de blocage |
| 50 to 54 | block | Le serveur de réception a refusé l'IP d'envoi |
Toute classe en dehors de cette liste correspond à undetermined. Seuls les rebonds hard suppriment l'adresse ; soft, block, admin et undetermined ne le font pas, car l'adresse peut encore être livrable.
Suppression automatique
Deux événements ajoutent automatiquement un destinataire à la liste de suppression de l'espace de travail, et ils bloquent des courriers différents :
| Événement | Suppression reason | Ce qu'il bloque |
|---|---|---|
| email.bounced or email.out_of_band_bounce with bounce_type: "hard" | hard_bounce | Tout le courrier, transactionnel inclus |
| email.complained | complaint | Courrier marketing ; le transactionnel est toujours envoyé |
Un rebond dur bloque tout car l'adresse elle-même n'existe plus. Une plainte ne bloque que le marketing, car quelqu'un qui a signalé votre newsletter comme spam a toujours besoin de sa réinitialisation de mot de passe.
email.unsubscribed et email.list_unsubscribed bloquent le courrier de la même façon qu'une plainte, le marketing uniquement, mais via un enregistrement différent : au lieu d'ajouter une suppression, ils enregistrent l'opt-out du destinataire comme une préférence déclarée. Ce que fait un opt-out couvre cet enregistrement en détail.
Chaque ajout déclenche un événement email_suppression.created qui contient le suppression_id, l'adresse supprimée email, le reason et le workspace_id. Le schéma complet de l'enregistrement et la gestion manuelle des entrées se trouvent dans le Guide des suppressions.
Les envois ultérieurs à une adresse supprimée sont rejetés d'emblée en tant que email.rejected avec rejection_reason: "recipient_suppressed", et ne comptent jamais contre votre délivrabilité.
Étapes suivantes
- Webhooks et événements : configuration de l'endpoint, vérification de signature, réessais et rejeu
- Suppressions : fonctionnement de la liste de suppression et gestion
- Liens de désinscription : mettre en place les chemins derrière email.unsubscribed et email.list_unsubscribed
- Test et sandbox : les envois sandbox émettent de vrais événements via le chemin normal, c'est le moyen le plus économique de tester votre handler
- Les webhooks bien faits : des événements de livraison fiables : une vidéo qui crée un webhook et observe l'arrivée des événements
Ressources associées
Poursuivez avec la documentation, les guides et les exemples sur ce sujet. Les ressources sont en anglais.
Regarder le guideGetting started with emailExplorer la fonctionnalitéEmailSuivre le parcours d'apprentissageBuild your first integrationGuide d'implémentationSend your first email
Essayez la pratique et obtenez un guide d'implémentation