E-mailevents
We zenden events uit terwijl elke ontvanger de bezorging doorloopt. Een verzending naar drie adressen levert drie onafhankelijke stromen op, gecorreleerd via email_id en recipient_id. Deze pagina beschrijft de e-maileventtypen. Zie Webhooks voor handtekeningen, retries, volgorde en replay.
Elke ontvanger begint bij email.accepted en daarna email.processed. Een broadcast-ontvanger is een eigen bericht, dus krijgt ook een eigen email.accepted, maar alleen in de events API en het e-maillog, niet als webhook. Vanaf daar wordt het bericht geaccepteerd door de ontvangende server (email.delivered), uitgesteld en opnieuw geprobeerd (email.deferred, wat uiteindelijk resulteert in delivered of bounced), geweigerd door de ontvangende server (email.bounced), of er wordt helemaal geen bezorgpoging gedaan (email.rejected). Na een bezorging kan de stroom doorgaan met email.out_of_band_bounce, email.complained, email.opened, email.clicked, email.unsubscribed en email.list_unsubscribed.
Elke ontvanger eindigt in precies één eindstatus: delivered, bounced, complained of rejected, teruggegeven als de status per ontvanger van GET /v1/email/messages/{message_id}/recipients. Engagementevents veranderen die status nooit: een ontvanger die het bericht opende, is nog steeds delivered. Een late bounce verandert de status wél, omdat de ontvangende server een eerder gegeven acceptatie intrekt, waardoor de ontvanger van delivered naar bounced gaat. Het bericht als geheel heeft een eigen samenvattende status en tellingen per status op GET /v1/email/messages/{message_id}.
De event-envelope
Events komen binnen als de drievelds-envelope die elke webhook gebruikt: type, timestamp (wanneer het event plaatsvond, RFC 3339) en een typespecifiek data-object.
Codevoorbeeld
{
"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
}
}Elk uitgaand event bevat email_id, recipient_id, workspace_id, het recipient-adres en de bijbehorende envelope recipient_role (to, cc of bcc). Het echoot ook tags en metadata uit het verzendverzoek, zodat je het event kunt koppelen aan je eigen administratie. Elke optionele waarde is null als de verzending er geen had, inclusief broadcast_id: dat veld noemt de broadcast waar een verzending deel van uitmaakte, zodat je de events van een broadcast kunt groeperen zonder elke verzending op te zoeken, en het is null bij een verzending zonder broadcast erachter. Eén geval rapporteert null voor een verzending die er wel een had: een uitschrijflink van e-mail die is verstuurd voordat we het veld toevoegden noemt geen broadcast, dus een opt-out via zo'n link rapporteert null op email.unsubscribed en email.list_unsubscribed, ongeacht of een broadcast de e-mail verzond. Beschouw null op die twee events als niet-conclusief, anders tel je de opt-outs van een broadcast te laag. broadcast_id ontvang je alleen via de webhook: de events API hieronder geeft elk event zonder dat veld terug. Eventtypen voegen velden toe die beschreven staan in de secties lifecycle, engagement, suppression en inbound.
Dezelfde events zijn achteraf opvraagbaar via GET /v1/email/messages/{message_id}/events, waar elk event ook een id (ev_-prefix) en een occurred_at heeft. Gebruik dit om bij te vullen, opnieuw af te spelen of af te stemmen met wat je endpoint ontving. Enkele velden ontvang je alleen via die API in plaats van via de webhook; de betreffende eventbeschrijving vermeldt welke dat zijn.
Lifecycle-events
email.accepted
We hebben de verzending geaccepteerd en zijn begonnen met het voorbereiden van de bezorging. Wordt één keer per gevraagde ontvanger afgevuurd en is het eerste event in die stroom. Een broadcast-ontvanger krijgt er ook één, omdat elke ontvanger een eigen bericht is, maar het wordt geregistreerd in plaats van bezorgd: lees het uit de events API of het e-maillog, niet via je webhook-endpoint. Payload: alleen de identiteitsbasis.
email.processed
Het bericht is opgebouwd en in de wachtrij geplaatst voor bezorging aan de mailserver van de ontvanger. Payload: alleen de identiteitsbasis via de webhook; de events API voegt mailbox_provider en mailbox_provider_region toe, de classificatie van het ontvangende mailsysteem (bijvoorbeeld gmail, NA), aanwezig wanneer die bepaald kon worden en anders null. Door de timestamp van dit event te vergelijken met die van email.accepted krijg je onze eigen verwerkingstijd voor een enkele verzending. Een broadcast heeft zo'n interval niet: de acceptatie en de verwerking dragen hetzelfde verzendmoment, dus de twee timestamps komen overeen in plaats van verwerkingstijd te omsluiten, en de acceptatie ontvang je alleen via de events API, als occurred_at.
email.delivered
De ontvangende mailserver heeft het bericht geaccepteerd en de verantwoordelijkheid ervoor op zich genomen. Dit event bevestigt geen inboxplaatsing of lezing. Inbox Insights biedt steekproefsgewijze plaatsingsschattingen; open- en klikevents registreren trackingverzoeken. Payload: alleen de identiteitsbasis via de webhook; de events API voegt sending_ip toe, het adres van waaruit het bericht is verzonden, wat ertoe doet als een bezorgbaarheidsprobleem naar één IP wijst, plus mailbox_provider en mailbox_provider_region.
email.deferred
Een tijdelijke fout: de ontvangende server vroeg ons het later opnieuw te proberen (volle mailbox, greylisting, beperking van het aantal verzoeken). We proberen automatisch opnieuw en de ontvanger resulteert uiteindelijk in email.delivered of email.bounced, dus dit event is informatief en niet terminaal, en een ontvanger kan meerdere keren worden uitgesteld. Payload: bounce_type, bounce_class, defer_reason (de reden die de server opgaf) en sending_ip via de webhook; de events API voegt mailbox_provider en mailbox_provider_region toe.
Failure-events
email.bounced
Een permanente fout op SMTP-moment: de ontvangende server weigerde het bericht en de eindstatus van de ontvanger wordt bounced. Payload: bounce_type (zie de classificatietabel), bounce_class, bounce_code (de SMTP-antwoordcode, bijvoorbeeld 550), bounce_description (de reden die de server opgaf) en sending_ip via de webhook; de events API voegt mailbox_provider en mailbox_provider_region toe. Een hard bounce onderdrukt het adres.
email.out_of_band_bounce
Een late bounce: de ontvangende server accepteerde het bericht op SMTP-moment en stuurde daarna een bouncerapport. Het heeft dezelfde classificatie als email.bounced (bounce_type, bounce_class, bounce_code, bounce_description, sending_ip via de webhook; mailbox_provider en mailbox_provider_region uit de events API). Wanneer het rapport als bounce wordt geclassificeerd (elke klasse in de tabel), heeft de server de eerdere acceptatie ingetrokken en gaat de ontvanger van delivered naar bounced. Rapporten met een klasse die niet in de tabel staat, zoals auto-replies, worden op de tijdlijn geregistreerd en laten de status ongewijzigd. Een hard out-of-band bounce onderdrukt het adres eveneens.
email.rejected
De ontvanger heeft de externe mailserver nooit bereikt, dus er is geen bezorgpoging gedaan. Dat onderscheidt een rejection van een bounce, waarbij de ontvangende server degene is die nee zegt. Payload: rejection_reason, ook op het ontvangerrecord, een van:
| rejection_reason | Betekenis |
|---|---|
| recipient_suppressed | De ontvanger is geblokkeerd op werkruimteniveau, door de suppressielijst of door een opgegeven voorkeur, dus er is nooit een bezorgpoging gedaan |
| transmission_failed | Het bericht kon niet worden verzonden voor bezorging |
| generation_failure | Het bericht kon niet worden opgebouwd voor bezorging, een template- of inhoudsprobleem |
| policy_rejection | Het verzendbeleid weigerde het bericht |
| domain_unverified | Het verzenddomein was niet geverifieerd |
| quota_exceeded | Het verzendquotum van de organisatie was bereikt |
| recipient_not_allowed | De ontvanger was niet toegestaan voor deze verzending; verzendingen via een gedeeld onboardingdomein bereiken alleen geverifieerde leden van je werkruimte |
De events API voegt ook mailbox_provider en mailbox_provider_region toe wanneer het ontvangende mailsysteem vóór de afwijzing geclassificeerd kon worden.
email.complained
De ontvanger markeerde het bericht als spam en de mailboxprovider meldde dit terug via zijn feedbackloop. Klachten komen binnen na bezorging en zetten de eindstatus op complained. Payload: feedback_type, het soort rapport dat de provider stuurde, zoals abuse of fraud, en null wanneer de provider dit niet specificeerde, plus mailbox_provider en mailbox_provider_region uit de events API. Een klacht onderdrukt het adres voor marketingmail. Houd je klachtratio laag: providers vertragen afzenders die rapporten verzamelen.
Engagementevents
email.opened
De trackingpixel in de berichttekst is geladen. Payload: ip_address en user_agent wanneer bekend; de events API voegt is_prefetched, country (ISO 3166-1 alpha-2, afgeleid van het client-IP), mailbox_provider en mailbox_provider_region toe. Controleer is_prefetched voordat je een open telt. Het is true wanneer een privacyfunctie van de inbox de pixel automatisch ophaalde in plaats van dat een persoon het bericht opende, en het meetellen daarvan blaast je openratio op. Open- en kliktracking behandelt de instrumentatie.
email.clicked
De ontvanger klikte op een getrackte link. Payload: url (de aangeklikte link), ip_address en user_agent wanneer bekend; de events API voegt country, mailbox_provider en mailbox_provider_region toe. Klikken zijn over het algemeen een sterker engagementsignaal dan opens, omdat privacyproxy's trackingpixels automatisch kunnen laden.
email.unsubscribed
De ontvanger gebruikte de uitschrijflink in de berichttekst. Payload: alleen de identiteitsbasis via de webhook; de events API voegt mailbox_provider en mailbox_provider_region toe. Registreert een opt-outvoorkeur die marketingmail blokkeert. Uitschrijflinks behandelt hoe de link in je mail terechtkomt.
email.list_unsubscribed
De ontvanger gebruikte de one-click-uitschrijfknop die de mailboxprovider in zijn eigen UI toont, aangestuurd door de List-Unsubscribe-headers van het bericht. Payload: alleen de identiteitsbasis via de webhook (plus mailbox_provider en mailbox_provider_region uit de events API); het mechanisme is het eventtype zelf, daarom is het gescheiden van email.unsubscribed. Registreert ook een opt-outvoorkeur die marketingmail blokkeert.
Berichtniveauevents
Twee events beschrijven het bericht als geheel in plaats van één ontvanger, dus hun data heeft email_id, workspace_id, tags en metadata maar geen ontvangeridentiteit. Beide horen bij geplande verzending.
email.scheduled
We hebben een verzending geaccepteerd met een scheduled_at in de toekomst. Payload: de berichtniveaubasis plus scheduled_at. Wanneer dat tijdstip aanbreekt, begint de lifecycle per ontvanger bij email.accepted.
email.canceled
Een gepland bericht is geannuleerd voordat het werd verzonden, dus het levert helemaal geen lifecycle-events per ontvanger op. Payload: alleen de berichtniveaubasis.
Inbound- en mailboxevents
email.received behandelt inkomende e-mail. Het wordt afgevuurd wanneer we een inbound bericht ontvangen en parsen. De payload bevat de inbound_message_id, adressering, onderwerp en authenticatieresultaten. Setup, payload en de fetch-back API staan in E-mail ontvangen. Een mailbox heeft daarbovenop een eigen email_mailbox.*-familie, behandeld in de mailboxgids.
Bounceclassificatie
bounce_class is de numerieke bounceclassificatie die is opgenomen bij email.bounced, email.out_of_band_bounce en email.deferred. Het vat samen in de grove bounce_type en behoudt de fijnmazige code, zodat je een volle mailbox nog kunt onderscheiden van een routeringsfout, ook al rapporteren beide als soft:
| bounce_class | bounce_type | Betekenis |
|---|---|---|
| 1 | undetermined | Het antwoord van de ontvangende server was dubbelzinnig |
| 10, 30 | hard | Permanente fout: ongeldig adres of een domein dat niet bestaat |
| 20 to 24, 40, 70, 100 | soft | Tijdelijke fout: volle mailbox, server tijdelijk onbereikbaar, DNS- of routeringsprobleem |
| 25 | admin | Administratieve weigering: relay geweigerd, domein op blocklist |
| 50 to 54 | block | De ontvangende server weigerde het verzendende IP |
Elke klasse buiten deze lijst wordt afgebeeld op undetermined. Alleen hard-bounces onderdrukken het adres; soft, block, admin en undetermined niet, omdat het adres mogelijk nog bezorgbaar is.
Auto-suppressie
Twee events voegen een ontvanger automatisch toe aan de suppressielijst van de werkruimte, en ze blokkeren verschillende soorten mail:
| Event | Suppressie reason | Wat het blokkeert |
|---|---|---|
| email.bounced of email.out_of_band_bounce met bounce_type: "hard" | hard_bounce | Alle mail, inclusief transactionele |
| email.complained | complaint | Marketingmail; transactionele wordt nog steeds verzonden |
Een hard bounce blokkeert alles, omdat het adres zelf niet meer bestaat. Een klacht blokkeert alleen marketing, omdat iemand die je nieuwsbrief als spam meldde nog steeds zijn wachtwoordreset nodig heeft.
email.unsubscribed en email.list_unsubscribed blokkeren mail op dezelfde manier als een klacht, alleen marketing, maar via een ander record: in plaats van een suppressie toe te voegen registreren ze de opt-out van de ontvanger als een opgegeven voorkeur. Wat een opt-out doet behandelt dat record volledig.
Elke toevoeging vuurt een email_suppression.created-event af met de suppression_id, het onderdrukte email, de reason en de workspace_id. Het volledige recordschema en hoe je handmatig vermeldingen beheert staan in de Suppressiegids.
Latere verzendingen naar een onderdrukt adres worden direct afgewezen als email.rejected met rejection_reason: "recipient_suppressed", en tellen nooit mee voor je bezorgbaarheid.
Volgende stappen
- Webhooks & events: endpoint instellen, handtekeningverificatie, retries en replay
- Suppressies: hoe de suppressielijst werkt en hoe je die beheert
- Uitschrijflinks: de paden achter email.unsubscribed en email.list_unsubscribed aansluiten
- Testen & sandbox: sandbox-verzendingen genereren echte events via het normale pad, de goedkoopste manier om je handler te testen
- Webhooks goed opgezet: betrouwbare bezorggebeurtenissen: een video die een webhook aanmaakt en de events laat binnenkomen
Gerelateerde bronnen
Ga verder met de documentatie, gidsen en voorbeelden voor dit onderwerp. De bronnen zijn in het Engels.
Bekijk de gidsGetting started with emailOntdek de mogelijkheidEmailVolg het leerpadBuild your first integrationImplementatiegidsSend your first email
Probeer de oefening en ontvang een implementatieoverzicht