Ga direct naar de documentatie
Kennisbank

Webhooks

Laat je endpoint weten wanneer er mail binnenkomt, in plaats van je te laten pollen.

Details

  • Vandaag al bruikbaar via Instellingen → Webhooks en via de API: registreer een https-endpoint, kies welke van de twintig events het wil hebben, en kopieer het whsec_-ondertekeningsgeheim, dat bij het aanmaken en bij het roteren wordt getoond en daarna nooit meer. Deliveries zijn echte ondertekende POSTs die door de mailbox zelf worden opgeworpen en niet door een API-aanroep, dus ze vuren op binnenkomende mail en op opens en kliks, wat het bericht ook heeft verstuurd. Versturen vuurt vanaf elk oppervlak, en dat gebeurde vroeger maar vanaf sommige: een verzending via de API, MCP, een template of een regel wierp email.sent op, terwijl een bericht vanuit het eigen opstelvenster van de app dat niet deed, omdat het opstelvenster rechtstreeks naar de mailbox schrijft en niet via de verzendservice die het event uitzond. Het event wordt nu bij de mailbox zelf opgeworpen, en daar komen ze allemaal samen, dus opstellen in de app, inplannen voor dinsdag en posten naar de API zijn drie manieren om dezelfde webhook te veroorzaken. Een uitgestelde verzending zegt het twee keer: email.scheduled of email.queued wanneer die wordt geaccepteerd, email.sent wanneer die daadwerkelijk vertrekt, en email.cancelled als je hem er tussenin terugtrekt. Tien endpoints per mailbox, afgedwongen overal waar er een wordt geregistreerd en niet alleen op dit scherm.
  • De events komen in drie families. Vijftien gaan over één bericht: email.received, email.replied, email.sent, email.delivered, email.failed, email.cancelled, email.scheduled, email.queued (de undo-send-tegenhanger van scheduled), email.delivery_delayed, email.bounced, email.complained, email.suppressed, email.opened, email.clicked en email.downloaded. email.sent betekent dat de verzendservice het bericht heeft geaccepteerd, email.delivered dat de ontvangende server dat heeft gedaan, en email.delivery_delayed dat het nog niet is aangekomen en nog steeds opnieuw wordt geprobeerd. email.replied vuurt samen met email.received wanneer het binnenkomende bericht er een beantwoordt dat al in de mailbox staat, dus een consumer die beide wil, krijgt ze beide. email.downloaded vuurt wanneer iemand een bestand ophaalt dat als downloadlink is meegegaan, waarbij dezelfde classifier scanners en linkvoorbeelden buiten de telling houdt, en het noemt geen ontvanger, omdat de link voor iedereen naar wie het bericht ging dezelfde is. Drie gaan over een domein: domain.verified wanneer het begint te ontvangen, domain.sending_changed wanneer het verzendoordeel verschuift, en domain.deleted wanneer het wordt verwijderd, of je daar nu om vroeg of de opruimer na zeven dagen het ongeverifieerd liet vallen. Twee gaan over de suppressielijst zelf, wat iets anders is dan email.suppressed: suppression.added wanneer er een adres op komt, suppression.removed wanneer er weer een wordt toegelaten. Je op geen enkel event abonneren betekent elk berichtevent behalve email.replied, vandaag veertien, nooit een familie die er later bij komt, en de API leest dat terug als ["*"]. Noem de events die je wilt als je liever expliciet bent. Elke delivery draagt X-OpenEmail-Signature als t=<unix>,v1=<hex>, een HMAC-SHA-256 over het tijdstempel, een punt en de ruwe body, plus X-OpenEmail-Event en X-OpenEmail-Delivery. Verifieer tegen de bytes zoals ze binnenkwamen: parsen en opnieuw serialiseren herschikt de sleutels en breekt de handtekening. Het replayvenster van 300 seconden is aan de ontvanger om af te dwingen, en de verifier van de SDK gaat daar standaard van uit.
  • Registratie wordt geweigerd voor alles wat geen https is of niet publiek routeerbaar (loopback, RFC1918, link-local, CGNAT en de IPv6-equivalenten), en redirects worden niet gevolgd, dus een 3xx wordt vastgelegd als een mislukte delivery in plaats van ergens anders achterna te worden gezeten. De ontvanger krijgt 5 seconden, endpoints worden parallel bediend zodat tien ervan nog steeds 5 seconden kosten in plaats van 50, en recente pogingen staan op de pagina van dat endpoint vermeld met de responscode en hoe lang het duurde.
  • Een delivery wordt tot vijf keer geprobeerd. De eerste gaat uit op het moment dat het event plaatsvindt; een fout die zichzelf aannemelijk kan oplossen wordt na 1 minuut opnieuw geprobeerd, dan na 5, dan na 25, dan na 2 uur, wat één event over ongeveer tweeënhalf uur uitsmeert. Nieuwe pogingen worden als duurzaam werk bewaard en niet in het geheugen, dus een deploy midden in dat venster raakt ze niet kwijt. Alleen fouten die het herhalen waard zijn worden herhaald: een time-out, een geweigerde verbinding, 408, 425, 429 of elke 5xx. Elke andere 4xx is het endpoint dat de payload bewust weigert, en nog vier keer vragen zou vier keer de belasting zijn voor hetzelfde antwoord. De event-id wordt één keer aangemaakt en elke poging draagt hem mee in X-OpenEmail-Delivery, zodat een ontvanger die dezelfde id twee keer ziet de tweede kan laten vallen in plaats van er twee keer naar te handelen. Nadat 100 events op rij bij elke poging mislukken, wordt het endpoint uitgeschakeld, krijgt de workspace een e-mail, en is de reden op het endpoint zelf te lezen. Een endpoint dat 410 Gone antwoordt, wordt ter plekke uitgeschakeld.
  • Een endpoint dat 100 keer op rij faalt, wordt uitgezet in plaats van eindeloos gebeld, en iedereen met toegang tot webhooks krijgt daar een e-mail over: welk endpoint, wat de laatste poging meldde, en dat er niets in de wachtrij is gezet terwijl het faalde. De teller is OPEENVOLGEND en elke geslaagde poging zet hem terug, zodat een slechte middag afgelopen maart niet kan optellen tot een uitgeschakeld endpoint vandaag. Het weer aanzetten wist de teller mee. De console maakt onderscheid tussen de twee toestanden in plaats van één schakelaar te tonen: een endpoint dat jij hebt uitgezet ziet er anders uit dan een endpoint dat wij hebben uitgezet.
  • Endpoints beheren is één taak met twee voordeuren. Via de API zijn dat POST /webhooks, de patch, de delete, rotate-secret, test en het deliverylogboek, met voor elk een methode in de SDK; in de app is het Instellingen → Webhooks, tegen hetzelfde register en niet tegen een tweede. Lezen is afgeschermd met webhooks:read, zodat iedereen die aan een integratie bouwt de endpoints en hun deliverygeschiedenis kan zien (welke vuurde, wat de ontvanger antwoordde, hoe lang het duurde) zonder de eigenaar te zijn. Registreren, bewerken, testen, roteren en verwijderen vereisen webhooks:write ÉN eigendom van de mailbox, op beide oppervlakken, en die tweede helft is met opzet: een endpoint heeft geen adres-as, dus het ontvangt elk adres dat de workspace heeft, met onderwerpen en ontvangers erbij, en geen enkele permissie betekent “mag dat allemaal toegestuurd krijgen”. Een rol die integraties bouwt en de mail niet leest, bedient het in plaats daarvan met een workspace-sleutel.