Event-Typen
Abonniere beim Erstellen eines Webhooks eine beliebige Kombination dieser Event-Typen.
| Event | Wird ausgelöst, wenn | Setzt last_event auf |
|---|---|---|
email.scheduled |
Eine E-Mail mit scheduled_at angenommen wurde. |
scheduled |
email.sent |
die E-Mail an Amazon SES übergeben wurde. | sent |
email.delivered |
der Mailserver des Empfängers die E-Mail angenommen hat. | delivered |
email.delivery_delayed |
die Zustellung verzögert ist oder vorübergehend fehlschlägt; SES versucht es weiter. | delivery_delayed |
email.bounced |
ein dauerhafter Fehler vorliegt (die Adresse existiert nicht, die Domain lehnt ab). | bounced |
email.complained |
der Empfänger die E-Mail als Spam markiert hat. | complained |
email.opened |
der Empfänger die E-Mail geöffnet hat (erfordert Öffnungs-Tracking). | opened |
email.clicked |
der Empfänger auf einen Link geklickt hat (erfordert Klick-Tracking). | clicked |
email.failed |
SpacePost oder SES die E-Mail nicht senden konnte (abgelehnt, Rendering-Fehler, pausiertes Team oder pausierter Tenant). | failed |
email.suppressed |
ein Empfänger übersprungen wurde, weil er auf deiner Sperrliste steht. | suppressed |
Aufbau der Payload
Abschnitt betitelt „Aufbau der Payload“Webhook-Bodys entsprechen exakt denen von Resend, sodass für Resend geschriebene Handler weiter funktionieren.
{ "type": "email.delivered", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "broadcast_id": "0192e1c4-0000-7000-8000-0000000000bb", "tenant_id": "0192e1c4-5555-7000-8000-0000000000cc", "tags": { "category": "welcome" } }}typeist das Event;created_atist der Zeitpunkt, zu dem das Event eingetreten ist.data.email_id,from,to(alle Empfänger der E-Mail, nicht nur der betroffene),subjectundcreated_at(wann die E-Mail erstellt wurde) sind immer vorhanden.data.broadcast_idist nur bei E-Mails aus Kampagnen vorhanden.data.tenant_idist nur vorhanden, wenn die E-Mail für einen Tenant gesendet wurde (Plattform-Modus). Es ist unsere Tenant-ID, nicht deineexternal_id.data.tagsist nur vorhanden, wenn die E-Mail Tags hatte, und zwar als Objekt ({ "name": "value" }).- Manche Events fügen
dataein weiteres Objekt hinzu, das nach dem Event benannt ist:bounce,click,open,failedodersuppressed. Sie sind unten aufgeführt. Mehr wird nicht hinzugefügt: Es gibt keine SchlüsselbounceType,delayTypeoderreasonauf oberster Ebene.
Beispiele
Abschnitt betitelt „Beispiele“email.scheduled
Abschnitt betitelt „email.scheduled“{ "type": "email.scheduled", "created_at": "2026-10-23T14:02:09.700Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Your trial ends tomorrow", "created_at": "2026-10-23T14:02:09.512Z" }}email.sent
Abschnitt betitelt „email.sent“{ "type": "email.sent", "created_at": "2026-10-23T14:02:10.100Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.delivered
Abschnitt betitelt „email.delivered“{ "type": "email.delivered", "created_at": "2026-10-23T14:02:11.350Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.delivery_delayed
Abschnitt betitelt „email.delivery_delayed“Wird bei Zustellverzögerungen von SES und bei vorübergehenden Bounces ausgelöst. Für eine reine Verzögerung gibt es keine zusätzlichen Felder. Ein vorübergehender Bounce enthält zusätzlich das Objekt bounce (siehe unten, mit type: "Transient").
{ "type": "email.delivery_delayed", "created_at": "2026-10-23T14:07:00.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.bounced
Abschnitt betitelt „email.bounced“Dieses Event erreichen nur dauerhafte Bounces, und sie tragen die Adresse in deine Sperrliste ein. data.bounce enthält type (Permanent), subType und die message des empfangenden Servers.
{ "type": "email.bounced", "created_at": "2026-10-23T14:02:12.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["nobody@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "bounce": { "type": "Permanent", "subType": "General", "message": "smtp; 550 5.1.1 The email account that you tried to reach does not exist." } }}Zu den Bounce-Untertypen gehören General, NoEmail, Suppressed, OnAccountSuppressionList, MailboxFull, MessageTooLarge, ContentRejected und AttachmentRejected.
email.complained
Abschnitt betitelt „email.complained“Keine zusätzlichen Felder. Die Adresse wird deiner Sperrliste hinzugefügt.
{ "type": "email.complained", "created_at": "2026-10-23T15:30:00.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Our monthly newsletter", "created_at": "2026-10-23T14:02:09.512Z" }}email.opened
Abschnitt betitelt „email.opened“{ "type": "email.opened", "created_at": "2026-10-23T14:05:44.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "open": { "ipAddress": "203.0.113.7", "userAgent": "Mozilla/5.0 (Macintosh)" } }}email.clicked
Abschnitt betitelt „email.clicked“{ "type": "email.clicked", "created_at": "2026-10-23T14:06:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "click": { "link": "https://acme.com/get-started", "ipAddress": "203.0.113.7", "userAgent": "Mozilla/5.0 (Macintosh)", "timestamp": "2026-10-23T14:06:10.000Z" } }}email.failed
Abschnitt betitelt „email.failed“{ "type": "email.failed", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "failed": { "reason": "Attachment https://files.acme.com/report.pdf returned HTTP 404" } }}email.suppressed
Abschnitt betitelt „email.suppressed“suppressed.reason ist suppression_list (der Empfänger steht auf deiner Sperrliste) oder recipient_domain_does_not_accept_mail (die Domain des Empfängers hat keinen Mailserver).
{ "type": "email.suppressed", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com", "other@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "suppressed": { "recipients": ["other@example.com"], "reason": "suppression_list" } }}Events in TypeScript typisieren
Abschnitt betitelt „Events in TypeScript typisieren“Das Node SDK exportiert eine Union WebhookPayload, die über type unterschieden wird, und spacepost.webhooks.verify() gibt sie zurück. Wenn du auf event.type einengst, bekommst du die passenden data-Felder:
import type { WebhookPayload } from "@spacepost/node";
function handle(event: WebhookPayload) { switch (event.type) { case "email.bounced": return event.data.bounce?.subType; case "email.clicked": return event.data.click?.link; case "email.suppressed": return event.data.suppressed.recipients; case "email.failed": return event.data.failed.reason; default: return event.data.tenant_id; // present when the email was sent for a tenant }}