From f9360cf45e19e8ee59afe435a88f8c7ee9aa1f40 Mon Sep 17 00:00:00 2001 From: Anton Tuyakhov <7713205+tuyakhov@users.noreply.github.com> Date: Thu, 30 Jul 2026 21:08:27 +0000 Subject: [PATCH] docs: document message.complained and message.suppressed webhook events Add the two delivery-outcome webhook events to the subscribable event lists so users know how to handle them: - message.complained: the recipient marked the message as spam. A complaint emits both message.complained and message.opted_out, so existing opt-out handlers keep working unchanged. - message.suppressed: a send was skipped because the address failed validation or was already on the suppression list after an earlier bounce or complaint. --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7aebcf2..188cb63 100644 --- a/README.md +++ b/README.md @@ -320,9 +320,14 @@ print(event.type, event.payload) # e.g. "message.delivered", {...} ``` Subscribable event types: `message.sent`, `message.delivered`, `message.failed`, -`message.opted_out`, `message.opened`, and `message.clicked`. The engagement -events (`message.opened` / `message.clicked`) never change a message's status, -and the `message.clicked` payload also carries the clicked `link`. +`message.opted_out`, `message.complained`, `message.suppressed`, `message.opened`, +and `message.clicked`. `message.complained` fires when the recipient marks the +message as spam; a complaint emits both `message.complained` and `message.opted_out`, +so handlers that only watch for opt-outs keep working unchanged. `message.suppressed` +fires when a send is skipped because the address failed validation or was already on +the suppression list after an earlier bounce or complaint. The engagement events +(`message.opened` / `message.clicked`) never change a message's status, and the +`message.clicked` payload also carries the clicked `link`. The framework integrations below wire this up for you.