Suppressies
Je werkruimte heeft een suppressielijst: een verzameling e-mailadressen waar we niet aan bezorgen. Hard bounces en spamklachten komen er automatisch op terecht, en je kunt zelf adressen toevoegen. Herhaaldelijk mailen naar adressen die bouncen of spam melden kan ertoe leiden dat mailboxproviders je domein blokkeren, dus we stoppen die verzendingen voordat ze het platform verlaten.
Een uitschrijving staat niet op deze lijst. Die registreert de eigen voorkeursverklaring van de ontvanger in plaats van een afleverbaarheidsvaststelling, en staat daarom op het tabblad Preferences. Zie Uitschrijflinks voor hoe dat werkt.
Beheer de lijst in Email > Suppressions, via de suppressions-API of met bird email suppressions.

De drie redenen en wat ze blokkeren
Elk record heeft een reason die aangeeft waarom het adres op de lijst staat, en een applies_to-beleid dat bepaalt welke categorieën het blokkeert:
| Reden | applies_to | Marketingcategorie | Transactionele categorie |
|---|---|---|---|
| hard_bounce | all | Geblokkeerd | Geblokkeerd |
| complaint | non_transactional | Geblokkeerd | Toegestaan |
| manual | all | Geblokkeerd | Geblokkeerd |
De verdeling volgt uit wat elke reden betekent:
- hard_bounce: het adres bestaat niet. Verzenden is zinloos in elke categorie, dus het blokkeert alles.
- complaint: een verklaring over ongewenste mail. Iemand die je nieuwsbrief als spam heeft gemeld, kan nog steeds een wachtwoordreset of een orderbevestiging nodig hebben, dus het blokkeert alleen niet-transactionele verzendingen.
- manual: een bewuste beslissing van jou of je team. We trekken die niet in twijfel, dus een handmatige suppressie blokkeert elke categorie, inclusief transactioneel.
Een adres heeft één record per reden, dus een hard bounce en een eerdere klacht staan naast elkaar als afzonderlijke records, en bezorging blijft geblokkeerd zolang er een blokkerend record bestaat. We kiezen bij onbekende waarden altijd voor blokkeren: als een record terugkomt met een applies_to die je integratie nog nooit heeft gezien, behandel het dan als blokkerend voor elke categorie, want zo behandelen wij het zelf ook.
Note: reason: unsubscribe is deprecated on the suppressions API. Unsubscribes now record a preference instead of a suppression, so ?reason=unsubscribe matches nothing.
Hoe adressen automatisch worden toegevoegd
We voegen suppressies toe op basis van signalen van ontvangers, dus een bounce of klacht vereist geen actie van jou:
| Trigger | Resulterende suppressie |
|---|---|
| Hard bounce (email.bounced) | reason: hard_bounce, origin: bounce_event, applies_to: all |
| Out-of-band hard bounce (email.out_of_band_bounce) | reason: hard_bounce, origin: bounce_event, applies_to: all |
| Spamklacht (email.complained) | reason: complaint, origin: complaint_event, applies_to: non_transactional |
Een uitschrijving, via de link in de berichttekst of de one-click-knop, verschijnt hier niet: die registreert een voorkeur op het tabblad Preferences in plaats van een rij aan deze lijst toe te voegen.
Alleen een bounce van de klasse hard leidt tot suppressie, en de classificatietabel toont welke bounce_class-waarden als hard tellen. Twee uitkomsten die op fouten lijken laten het adres verzendbaar:
- Soft bounces en deferrals (email.deferred, of email.bounced met bounce_type: "soft"): tijdelijke fouten zoals een volle mailbox. We proberen het opnieuw.
- Afwijzingen aan de verzendzijde: generatiefouten en beleidsafwijzingen zijn problemen met de verzending, niet met het adres. Ze produceren email.rejected-events en geen suppressie.
Herhaalde signalen voor een adres dat al is onderdrukt met dezelfde reden laten het oorspronkelijke record intact, inclusief de created_at. Het record behoudt source_email_id en source_recipient_id, die een automatische suppressie koppelen aan het exacte bericht en de ontvanger die het veroorzaakten. Die twee velden beantwoorden de supportvraag "why did this person stop getting our email", en ze zijn null bij handmatige toevoegingen.
Elke toevoeging, automatisch of handmatig, stuurt een email_suppression.created-event naar je webhook-endpoint met de suppression_id, het onderdrukte email, de reason en de workspace_id, zodat je eigen systeem de lijst kan spiegelen zonder te pollen:
Codevoorbeeld
{
"type": "email_suppression.created",
"timestamp": "2026-07-23T14:52:03.192524705Z",
"data": {
"email": "user@example.com",
"reason": "manual",
"suppression_id": "sup_01ky7qckqrf06r38g49b9kxdbc",
"workspace_id": "ws_01ky7m21hjffh9s8kq76gyb1xf"
}
}Suppressies beheren via de API
De API voegt toe, geeft weer, zoekt op en verwijdert afzonderlijke records. Adressen worden voor opslag en opzoeken naar kleine letters omgezet, en ze verschijnen nooit in een URL-pad, omdat een pad in toegangslogs belandt en een e-mailadres persoonsgegevens is. Om het record voor een adres te vinden filter je de lijst met ?email=.
De SDK-voorbeelden benaderen suppressies via de raw-requestmethode van elke client, die dezelfde authenticatie, retries en base-URL-afhandeling biedt als een getypte aanroep. De responsstructuur is degene die je declareert.
Een adres toevoegen
type Suppression = { id: string; email: string; reason: string };
const suppression = await bird.request<Suppression>({
method: "POST",
path: "/v1/email/suppressions",
body: { email: "user@example.com" },
});client.post("/v1/email/suppressions", body={"email": "user@example.com"})var suppression struct {
Id string `json:"id"`
Email string `json:"email"`
Reason string `json:"reason"`
}
if err := client.Post(context.Background(), "/v1/email/suppressions", map[string]any{
"email": "user@example.com",
}, &suppression); err != nil {
log.Fatal(err)
}$suppression = $bird->post('/v1/email/suppressions', body: [
'email' => 'user@example.com',
]);curl -X POST https://us1.platform.bird.com/v1/email/suppressions \
-H "Authorization: Bearer $BIRD_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "user@example.com" }'Op de CLI omvat bird email suppressions zowel list als remove; een adres toevoegen gaat via de API.
Handmatige toevoegingen krijgen reason: manual en applies_to: all, dus ze blokkeren elke categorie. De aanroep is idempotent: een nieuwe suppressie retourneert 201 Created, en een adres dat al handmatig is onderdrukt retourneert 200 OK met het bestaande record in plaats van een conflict. In beide gevallen is de body het suppressie-object:
Codevoorbeeld
{
"applies_to": "all",
"created_at": "2026-07-23T14:52:03.192524705Z",
"email": "user@example.com",
"id": "sup_01ky7qckqrf06r38g49b9kxdbc",
"origin": "api_key",
"reason": "manual",
"scope": {
"id": "ws_01ky7m21hjffh9s8kq76gyb1xf",
"type": "workspace"
}
}Het veld origin registreert hoe het record tot stand is gekomen. Handmatige toevoegingen krijgen api_key of user, afhankelijk van of de aanroeper zich heeft geauthenticeerd met een API-sleutel of een dashboardsessie. Automatische toevoegingen krijgen bounce_event of complaint_event, afhankelijk van welk signaal ze heeft aangemaakt.
Opvragen en opzoeken
type Suppressions = { data: Array<{ id: string; email: string; reason: string }> };
const suppressions = await bird.request<Suppressions>({
method: "GET",
path: "/v1/email/suppressions?limit=25",
});
console.log(suppressions.data.length);suppressions = client.get("/v1/email/suppressions?limit=25")
print(len(suppressions["data"]))var out struct {
Data []struct {
Email string `json:"email"`
Reason string `json:"reason"`
} `json:"data"`
}
if err := client.Get(context.Background(), "/v1/email/suppressions?limit=25", &out); err != nil {
log.Fatal(err)
}
fmt.Println(len(out.Data))$suppressions = $bird->get('/v1/email/suppressions', query: ['limit' => 25]);bird email suppressions list --limit 25curl "https://us1.platform.bird.com/v1/email/suppressions?limit=25" \
-H "Authorization: Bearer $BIRD_API_KEY"De lijst is cursor-gepagineerd, nieuwste eerst, en filterbaar op reason. Om één adres te controleren geef je het mee als de email-queryparameter:
const suppressions = await bird.request({
method: "GET",
path: "/v1/email/suppressions?email=user@example.com",
});
console.log(suppressions.data.length);suppressions = client.get("/v1/email/suppressions?email=user@example.com")
print(len(suppressions["data"]))var out struct {
Data []struct {
Email string `json:"email"`
Reason string `json:"reason"`
} `json:"data"`
}
if err := client.Get(context.Background(), "/v1/email/suppressions?email=user@example.com", &out); err != nil {
log.Fatal(err)
}
fmt.Println(len(out.Data))$suppressions = $bird->get('/v1/email/suppressions', query: ['email' => 'user@example.com']);bird email suppressions list --email user@example.comcurl "https://us1.platform.bird.com/v1/email/suppressions?email=user@example.com" \
-H "Authorization: Bearer $BIRD_API_KEY"Een lege data-array betekent dat het adres niet is onderdrukt, en er komen meerdere records terug als meer dan één reden van toepassing is. Het email-filter matcht hoofdletterongevoelig op prefix, dus een volledig adres retourneert de records van dat adres en een fragment zoals alice retourneert elk onderdrukt adres dat ermee begint.
Een adres verwijderen
await bird.request({
method: "DELETE",
path: "/v1/email/suppressions/sup_01ky7qckqrf06r38g49b9kxdbc",
});client.delete("/v1/email/suppressions/sup_01ky7qckqrf06r38g49b9kxdbc")if err := client.Delete(context.Background(), "/v1/email/suppressions/sup_01ky7qckqrf06r38g49b9kxdbc", nil); err != nil {
log.Fatal(err)
}$bird->delete('/v1/email/suppressions/sup_01ky7qckqrf06r38g49b9kxdbc');bird email suppressions remove sup_01ky7qckqrf06r38g49b9kxdbc --yescurl -X DELETE https://us1.platform.bird.com/v1/email/suppressions/sup_01ky7qckqrf06r38g49b9kxdbc \
-H "Authorization: Bearer $BIRD_API_KEY"Retourneert 204 No Content. De verwijdering is permanent: we bewaren niets, en het adres wordt weer verzendbaar. Verwijderen op adres kost twee aanroepen, een ?email=-opzoeking voor het ID en daarna de verwijdering, en een adres dat om meerdere redenen is onderdrukt vereist dat elk blokkerend record wordt verwijderd. Wees voorzichtig met het verwijderen van een hard_bounce-record, want een adres dat nog steeds niet bestaat bouncet bij de volgende verzending en onderdrukt zichzelf opnieuw.
Wat er gebeurt als je naar een onderdrukt adres verzendt
We wijzen de ontvanger af waar je het kunt zien. De ontvanger krijgt een recipient_id en verschijnt in de ontvangerlijst van het bericht met status rejected. De events API en je webhooks registreren een email.rejected-event met rejection_reason: "recipient_suppressed". De overige ontvangers worden normaal bezorgd.
Het bericht zelf wordt nog steeds geaccepteerd met een 202, ook als alle ontvangers zijn onderdrukt. We passen suppressie toe na het accepteren van de verzending, terwijl we het bericht verwerken, dus een adres dat je nu toevoegt is binnen enkele minuten van kracht en stopt nooit een verzending die al onderweg is.
Testen met de sandbox
De testsandbox test suppressieafhandeling deterministisch. Verzenden naar suppressed@messagebird.dev gedraagt zich alsof het adres op je lijst staat: de ontvanger wordt afgewezen met rejection_reason: "recipient_suppressed" en bereikt nooit de bezorging. De sandbox-bounce- en klachtadressen (bounce@messagebird.dev, complaint@messagebird.dev) doorlopen hun uitkomsten via de echte eventpipeline zonder iets naar je suppressielijst te schrijven, zodat dezelfde testadressen herbruikbaar blijven tussen runs.
Vervolgstappen
- Categorieën: transactional versus marketing, en hoe de categorie samenwerkt met het suppressiebeleid
- Uitschrijflinks: hoe opt-outs een voorkeursverklaring registreren in plaats van een suppressie
- Events en webhooks: de email.rejected-payload en de lifecycle-events die automatische suppressie aansturen
- Testsandbox: magische adressen om elke bezorguitkomst te simuleren
- API-referentie: Suppressions: volledige request- en responsschema's
- Wat er gebeurt wanneer iemand zich afmeldt: een video die één ontvanger volgt van de uitschrijfpagina tot een afgewezen verzending
Gerelateerde bronnen
Ga verder met de documentatie, gidsen en voorbeelden voor dit onderwerp. De bronnen zijn in het Engels.
Begrijp het conceptWhat is one-click unsubscribe, and how do I implement List-Unsubscribe?Ontdek de mogelijkheidEmail opt-outsVolg het leerpadOperate messaging reliably
Ontvang een implementatieoverzicht