Zdarzenia e-mail
Emitujemy zdarzenia w miarę jak każdy odbiorca przechodzi przez proces dostarczania. Wysyłka na trzy adresy generuje trzy niezależne strumienie, powiązane przez email_id i recipient_id. Ta strona definiuje typy zdarzeń e-mail. Zobacz Webhooki, aby poznać sygnatury, ponawianie, kolejność i odtwarzanie.
Każdy odbiorca zaczyna od email.accepted, potem email.processed. Odbiorca broadcastu jest osobną wiadomością, więc otrzymuje własne email.accepted, choć tylko w zdarzeniach API i logu e-mail, a nie jako webhook. Dalej wiadomość zostaje zaakceptowana przez serwer odbiorczy (email.delivered), zostaje odroczona i ponowiona (email.deferred, co kończy się dostarczeniem lub odrzuceniem), zostaje odrzucona przez serwer odbiorczy (email.bounced) lub w ogóle nie dochodzi do próby dostarczenia (email.rejected). Po dostarczeniu strumień może kontynuować z email.out_of_band_bounce, email.complained, email.opened, email.clicked, email.unsubscribed i email.list_unsubscribed.
Każdy odbiorca kończy dokładnie z jednym statusem końcowym: delivered, bounced, complained lub rejected, zwracanym jako status per odbiorca z GET /v1/email/messages/{message_id}/recipients. Zdarzenia zaangażowania nigdy go nie zmieniają: odbiorca, który otworzył wiadomość, nadal ma status delivered. Późny raport o odrzuceniu zmienia go, ponieważ serwer odbiorczy wycofuje wcześniej udzieloną akceptację, więc odbiorca przechodzi z delivered do bounced. Wiadomość jako całość ma własny zbiorczy status i liczniki per stan na GET /v1/email/messages/{message_id}.
Koperta zdarzenia
Zdarzenia docierają jako trzyelementowa koperta używana przez każdy webhook: type, timestamp (kiedy zdarzenie wystąpiło, RFC 3339) i obiekt data specyficzny dla danego typu.
Przykład kodu
{
"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
}
}Każde zdarzenie wychodzące zawiera email_id, recipient_id, workspace_id, adres recipient i kopertę recipient_role (to, cc lub bcc). Powtarza też tags i metadata z żądania wysyłki, dzięki czemu możesz powiązać zdarzenie ze swoimi rekordami. Każda opcjonalna wartość to null, gdy wysyłka jej nie zawierała, włącznie z broadcast_id: wskazuje broadcast, w ramach którego wysłano wiadomość, dzięki czemu możesz grupować zdarzenia broadcastu bez wyszukiwania każdej wysyłki z osobna; wynosi null przy wysyłce bez broadcastu. W jednym przypadku raportowane jest null dla wysyłki, która broadcast miała: link rezygnacji z subskrypcji z wiadomości wysłanej zanim dodaliśmy to pole nie wskazuje żadnego broadcastu, więc rezygnacja przez taki link raportuje null w email.unsubscribed i email.list_unsubscribed niezależnie od tego, czy broadcast wysłał tę wiadomość. Traktuj null w tych dwóch zdarzeniach jako niekonkluzywne, w przeciwnym razie zaniżysz liczbę rezygnacji broadcastu. broadcast_id dociera do Ciebie tylko przez webhook: API poniżej zwraca każde zdarzenie bez niego. Typy zdarzeń dodają pola opisane w sekcjach cyklu życia, zaangażowania, supresji i ruchu przychodzącego.
Te same zdarzenia można odpytywać po fakcie z GET /v1/email/messages/{message_id}/events, gdzie każde z nich ma też id (prefiks ev_) i occurred_at. Użyj go do uzupełniania, odtwarzania lub uzgadniania z tym, co odebrał Twój endpoint. Kilka pól dociera do Ciebie tylko przez to API, a nie przez webhook; odpowiedni opis zdarzenia wskazuje każde z nich.
Zdarzenia cyklu życia
email.accepted
Przyjęliśmy wysyłkę i rozpoczęliśmy przygotowanie dostarczenia. Emitowane raz na żądanego odbiorcę i jest pierwszym zdarzeniem w tym strumieniu. Odbiorca broadcastu również je otrzymuje, ponieważ każdy odbiorca jest osobną wiadomością, ale jest ono rejestrowane, a nie dostarczane: odczytaj je z API lub logu e-mail, a nie z endpointu webhooka. Payload: tylko baza tożsamości.
email.processed
Wiadomość została zbudowana i umieszczona w kolejce do dostarczenia na serwer pocztowy odbiorcy. Payload: tylko baza tożsamości przez webhook; API dodaje mailbox_provider i mailbox_provider_region, klasyfikację odbiorczego systemu pocztowego (na przykład gmail, NA), obecną gdy udało się ją ustalić, a w przeciwnym razie null. Porównanie timestamp tego zdarzenia z email.accepted daje czas naszego przetwarzania pojedynczej wysyłki. Broadcast nie ma takiego interwału: jego akceptacja i przetworzenie mają ten sam moment wysyłki, więc oba znaczniki czasu się pokrywają zamiast obejmować jakiekolwiek przetwarzanie, a akceptacja dociera do Ciebie tylko przez API jako occurred_at.
email.delivered
Serwer pocztowy odbiorcy zaakceptował wiadomość i przejął za nią odpowiedzialność. To zdarzenie nie potwierdza umieszczenia w skrzynce odbiorczej ani przeczytania. Inbox Insights dostarcza szacunki umieszczenia na próbie; zdarzenia otwarć i kliknięć rejestrują żądania śledzenia. Payload: tylko baza tożsamości przez webhook; API dodaje sending_ip, adres, z którego wysłano wiadomość, co ma znaczenie, gdy problem z dostarczalnością dotyczy jednego IP, oraz mailbox_provider i mailbox_provider_region.
email.deferred
Tymczasowa awaria: serwer odbiorczy poprosił o ponowną próbę później (pełna skrzynka, greylisting, ograniczanie liczby żądań). Ponawiamy automatycznie, a odbiorca ostatecznie kończy jako email.delivered lub email.bounced, więc to zdarzenie jest informacyjne, nie końcowe, a odbiorca może zostać odroczony kilka razy wcześniej. Payload: bounce_type, bounce_class, defer_reason (powód podany przez serwer) i sending_ip przez webhook; API dodaje mailbox_provider i mailbox_provider_region.
Zdarzenia błędów
email.bounced
Trwała awaria w momencie SMTP: serwer odbiorczy odrzucił wiadomość, a status końcowy odbiorcy zmienia się na bounced. Payload: bounce_type (zobacz tabelę klasyfikacji), bounce_class, bounce_code (kod odpowiedzi SMTP, na przykład 550), bounce_description (powód podany przez serwer) i sending_ip przez webhook; API dodaje mailbox_provider i mailbox_provider_region. Twarde odrzucenie blokuje adres.
email.out_of_band_bounce
Późne odrzucenie: serwer odbiorczy zaakceptował wiadomość w momencie SMTP, a następnie wysłał raport o odrzuceniu. Ma tę samą klasyfikację co email.bounced (bounce_type, bounce_class, bounce_code, bounce_description, sending_ip przez webhook; mailbox_provider i mailbox_provider_region z API). Gdy raport klasyfikuje się jako odrzucenie (dowolna klasa w tabeli), serwer wycofał wcześniejszą akceptację, więc odbiorca przechodzi z delivered do bounced. Raporty, których klasa nie znajduje się w tabeli, na przykład automatyczne odpowiedzi, są rejestrowane na osi czasu i nie zmieniają statusu. Twarde późne odrzucenie również blokuje adres.
email.rejected
Odbiorca nigdy nie dotarł do zdalnego serwera pocztowego, więc nie podjęto próby dostarczenia. To właśnie odróżnia odrzucenie od bounce'a, gdzie to serwer odbiorczy mówi nie. Payload: rejection_reason, również w rekordzie odbiorcy, jedna z wartości:
| rejection_reason | Znaczenie |
|---|---|
| recipient_suppressed | Odbiorca jest zablokowany na poziomie obszaru roboczego przez listę supresji lub zadeklarowaną preferencję, więc nie podjęto próby dostarczenia |
| transmission_failed | Wiadomość nie mogła zostać przesłana do dostarczenia |
| generation_failure | Wiadomość nie mogła zostać zbudowana do dostarczenia, problem z szablonem lub treścią |
| policy_rejection | Polityka wysyłki odrzuciła wiadomość |
| domain_unverified | Domena wysyłająca nie została zweryfikowana |
| quota_exceeded | Limit wysyłki organizacji został osiągnięty |
| recipient_not_allowed | Odbiorca nie był dozwolony dla tej wysyłki; wysyłki na współdzielonej domenie onboardingowej trafiają wyłącznie do zweryfikowanych członków Twojego obszaru roboczego |
API dodaje też mailbox_provider i mailbox_provider_region, gdy odbiorczy system pocztowy mógł zostać sklasyfikowany przed odrzuceniem.
email.complained
Odbiorca oznaczył wiadomość jako spam, a dostawca skrzynki zgłosił to z powrotem przez swoją pętlę zwrotną. Skargi docierają po dostarczeniu i ustawiają status końcowy na complained. Payload: feedback_type, rodzaj raportu wysłanego przez dostawcę, na przykład abuse lub fraud, oraz null gdy dostawca tego nie określił, plus mailbox_provider i mailbox_provider_region z API. Skarga blokuje adres dla wiadomości marketingowych. Utrzymuj niski wskaźnik skarg: dostawcy ograniczają nadawców, którzy zbierają raporty.
Zdarzenia zaangażowania
email.opened
Piksel śledzący w treści wiadomości został załadowany. Payload: ip_address i user_agent gdy znane; API dodaje is_prefetched, country (ISO 3166-1 alpha-2, określony na podstawie IP klienta), mailbox_provider i mailbox_provider_region. Sprawdź is_prefetched zanim zliczysz otwarcie. Przyjmuje wartość true, gdy funkcja prywatności skrzynki automatycznie pobrała piksel zamiast osoby otwierającej wiadomość, a zliczanie takich przypadków zawyża wskaźnik otwarć. Śledzenie otwarć i kliknięć opisuje instrumentację.
email.clicked
Odbiorca kliknął śledzony link. Payload: url (kliknięty link), ip_address i user_agent gdy znane; API dodaje country, mailbox_provider i mailbox_provider_region. Kliknięcia są na ogół silniejszym sygnałem zaangażowania niż otwarcia, ponieważ proxy prywatności mogą automatycznie ładować piksele śledzące.
email.unsubscribed
Odbiorca użył linku rezygnacji z subskrypcji w treści wiadomości. Payload: tylko baza tożsamości przez webhook; API dodaje mailbox_provider i mailbox_provider_region. Rejestruje preferencję rezygnacji, która blokuje wiadomości marketingowe. Linki rezygnacji z subskrypcji opisują, jak link trafia do Twojej wiadomości.
email.list_unsubscribed
Odbiorca użył przycisku rezygnacji z subskrypcji jednym kliknięciem, renderowanego przez dostawcę skrzynki w jego własnym interfejsie, sterowanego nagłówkami List-Unsubscribe wiadomości. Payload: tylko baza tożsamości przez webhook (plus mailbox_provider i mailbox_provider_region z API); mechanizmem jest sam typ zdarzenia, dlatego jest oddzielony od email.unsubscribed. Również rejestruje preferencję rezygnacji, która blokuje wiadomości marketingowe.
Zdarzenia na poziomie wiadomości
Dwa zdarzenia opisują wiadomość jako całość, a nie pojedynczego odbiorcę, więc ich data zawiera email_id, workspace_id, tags i metadata, ale nie zawiera tożsamości odbiorcy. Oba należą do wysyłki zaplanowanej.
email.scheduled
Przyjęliśmy wysyłkę z scheduled_at w przyszłości. Payload: baza na poziomie wiadomości plus scheduled_at. Gdy ten czas nadejdzie, cykl życia per odbiorca zaczyna się od email.accepted.
email.canceled
Zaplanowana wiadomość została anulowana zanim została wysłana, więc nie generuje żadnych zdarzeń cyklu życia odbiorcy. Payload: tylko baza na poziomie wiadomości.
Zdarzenia przychodzące i skrzynkowe
email.received obejmuje pocztę przychodzącą. Emitowane, gdy odbieramy i parsujemy wiadomość przychodzącą. Payload zawiera inbound_message_id, adresowanie, temat i werdykty uwierzytelniania. Konfiguracja, payload i API do pobierania są opisane w Odbieranie e-mail. Skrzynka ma własną rodzinę email_mailbox.*, opisaną w przewodniku po skrzynkach.
Klasyfikacja odrzuceń
bounce_class to numeryczna klasyfikacja odrzuceń dołączana do email.bounced, email.out_of_band_bounce i email.deferred. Agreguje się do ogólnej bounce_type i zachowuje szczegółowy kod, dzięki czemu możesz odróżnić pełną skrzynkę od błędu routingu, mimo że oba raportują się jako soft:
| bounce_class | bounce_type | Znaczenie |
|---|---|---|
| 1 | undetermined | Odpowiedź serwera odbiorczego była niejednoznaczna |
| 10, 30 | hard | Trwała awaria: nieprawidłowy adres lub nieistniejąca domena |
| 20 to 24, 40, 70, 100 | soft | Tymczasowa awaria: pełna skrzynka, serwer tymczasowo niedostępny, problem z DNS lub routingiem |
| 25 | admin | Odmowa administracyjna: przekazywanie odrzucone, zablokowana domena |
| 50 to 54 | block | Serwer odbiorczy odrzucił wysyłające IP |
Każda klasa spoza tej listy mapuje się na undetermined. Tylko odrzucenia hard blokują adres; soft, block, admin i undetermined nie, ponieważ adres może nadal być dostarczalny.
Automatyczna supresja
Dwa zdarzenia automatycznie dodają odbiorcę do listy supresji obszaru roboczego i blokują różne rodzaje wiadomości:
| Zdarzenie | Supresja reason | Co blokuje |
|---|---|---|
| email.bounced lub email.out_of_band_bounce z bounce_type: "hard" | hard_bounce | Wszystkie wiadomości, łącznie z transakcyjnymi |
| email.complained | complaint | Wiadomości marketingowe; transakcyjne nadal są wysyłane |
Twarde odrzucenie blokuje wszystko, ponieważ sam adres już nie istnieje. Skarga blokuje tylko marketing, ponieważ ktoś, kto zgłosił Twój newsletter jako spam, nadal potrzebuje resetu hasła.
email.unsubscribed i email.list_unsubscribed blokują wiadomości tak samo jak skarga, tylko marketing, ale przez inny rekord: zamiast dodawać supresję, rejestrują rezygnację odbiorcy jako zadeklarowaną preferencję. Co robi rezygnacja opisuje ten rekord w całości.
Każde dodanie emituje zdarzenie email_suppression.created, które zawiera suppression_id, zablokowany email, reason i workspace_id. Pełny schemat rekordu i sposób ręcznego zarządzania wpisami opisuje Przewodnik po supresjach.
Późniejsze wysyłki na zablokowany adres są od razu odrzucane jako email.rejected z rejection_reason: "recipient_suppressed" i nigdy nie wpływają na Twoją dostarczalność.
Następne kroki
- Webhooki i zdarzenia: konfiguracja endpointu, weryfikacja sygnatury, ponawianie i odtwarzanie
- Supresje: jak działa lista supresji i jak nią zarządzać
- Linki rezygnacji z subskrypcji: podłączanie ścieżek za email.unsubscribed i email.list_unsubscribed
- Testowanie i sandbox: wysyłki sandboxowe emitują prawdziwe zdarzenia normalną ścieżką, co jest najtańszym sposobem na przetestowanie Twojego handlera
- Webhooki bez kompromisów: niezawodne zdarzenia dostarczenia: film, który tworzy webhook i obserwuje napływające zdarzenia
Powiązane zasoby
Kontynuuj z dokumentacją, przewodnikami i przykładami dotyczącymi tego tematu. Zasoby są w języku angielskim.
Obejrzyj przewodnikGetting started with emailPoznaj możliwościEmailPodążaj ścieżką naukiBuild your first integrationPrzewodnik wdrożeniowySend your first email
Wypróbuj ćwiczenie i uzyskaj brief wdrożeniowy