Supressões
Seu espaço de trabalho possui uma lista de supressão: um conjunto de endereços de e-mail para os quais não fazemos entregas. Hard bounces e reclamações de spam entram nela automaticamente, e você também pode adicionar endereços manualmente. Enviar repetidamente para endereços que retornam bounce ou reportam spam pode fazer seu domínio ser bloqueado por provedores de caixa de entrada, por isso interrompemos esses envios antes que saiam da plataforma.
Um cancelamento de inscrição não está nesta lista. Ele registra a preferência declarada do próprio destinatário, e não um fato de entregabilidade, por isso fica na aba Preferences. Consulte Links de cancelamento de inscrição para saber como isso funciona.
Gerencie a lista em Email > Suppressions, pela API de supressões ou com bird email suppressions.

Os três motivos e o que eles bloqueiam
Cada registro tem um reason indicando por que o endereço está na lista e uma política applies_to que controla quais categorias ele bloqueia:
| Motivo | applies_to | Categoria marketing | Categoria transacional |
|---|---|---|---|
| hard_bounce | all | Bloqueada | Bloqueada |
| complaint | non_transactional | Bloqueada | Permitida |
| manual | all | Bloqueada | Bloqueada |
A divisão decorre do significado de cada motivo:
- hard_bounce: o endereço não existe. Enviar é inútil em qualquer categoria, então bloqueia tudo.
- complaint: uma declaração sobre e-mails indesejados. Alguém que reportou sua newsletter como spam ainda pode precisar de uma redefinição de senha ou de uma confirmação de pedido, então bloqueia apenas envios não transacionais.
- manual: uma decisão deliberada sua ou da sua equipe. Não a questionamos, então uma supressão manual bloqueia todas as categorias, incluindo transacional.
Um endereço pode ter um registro por motivo, então um hard bounce e uma reclamação anterior ficam lado a lado como registros separados, e a entrega permanece bloqueada enquanto qualquer registro bloqueante existir. Adotamos a postura mais restritiva para tudo que não reconhecemos: se um registro retornar com um applies_to que sua integração nunca viu, trate-o como bloqueando todas as categorias, que é como nós mesmos o tratamos.
Note: reason: unsubscribe is deprecated on the suppressions API. Unsubscribes now record a preference instead of a suppression, so ?reason=unsubscribe matches nothing.
Como endereços são adicionados automaticamente
Adicionamos supressões em resposta a sinais do destinatário, então um bounce ou reclamação não exige nenhuma ação sua:
| Gatilho | Supressão resultante |
|---|---|
| Hard bounce (email.bounced) | reason: hard_bounce, origin: bounce_event, applies_to: all |
| Hard bounce fora de banda (email.out_of_band_bounce) | reason: hard_bounce, origin: bounce_event, applies_to: all |
| Reclamação de spam (email.complained) | reason: complaint, origin: complaint_event, applies_to: non_transactional |
Um cancelamento de inscrição, seja pelo link no corpo do e-mail ou pelo botão de um clique, não aparece aqui: ele registra uma preferência na aba Preferences em vez de adicionar uma linha a esta lista.
Apenas bounces da classe hard geram supressão, e a tabela de classificação mostra quais valores de bounce_class contam como hard. Dois resultados que parecem falhas mantêm o endereço enviável:
- Soft bounces e adiamentos (email.deferred, ou email.bounced com bounce_type: "soft"): falhas temporárias como caixa de entrada cheia. Tentamos novamente.
- Rejeições do lado do envio: falhas de geração e rejeições de política são problemas com o envio, não com o endereço. Elas produzem eventos email.rejected e nenhuma supressão.
Sinais repetidos para um endereço que já está suprimido pelo mesmo motivo mantêm o registro original inalterado, incluindo seu created_at. O registro mantém source_email_id e source_recipient_id, que vinculam uma supressão automática à mensagem e ao destinatário exatos que a causaram. Esses dois campos respondem à pergunta de suporte "why did this person stop getting our email" e são null em adições manuais.
Toda adição, automática ou manual, dispara um evento email_suppression.created para seu endpoint de webhook com o suppression_id, o email suprimido, o reason e o workspace_id, para que seu próprio sistema possa espelhar a lista sem polling:
Exemplo de código
{
"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"
}
}Gerenciando supressões pela API
A API adiciona, lista, consulta e exclui registros individuais. Os endereços são convertidos para minúsculas antes do armazenamento e da consulta e nunca aparecem em um caminho de URL, porque caminhos vão para logs de acesso e um endereço de e-mail é dado pessoal. Para encontrar o registro de um endereço, filtre a lista com ?email=.
Os exemplos da SDK acessam supressões pelo método de requisição bruta de cada cliente, que inclui a mesma autenticação, tentativas de reenvio e tratamento de URL base de uma chamada tipada. O formato da resposta é o que você declara.
Adicionar um endereço
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" }'Na CLI, bird email suppressions cobre list e remove; adicionar um endereço é feito pela API.
Adições manuais recebem reason: manual e applies_to: all, então bloqueiam todas as categorias. A chamada é idempotente: uma nova supressão retorna 201 Created, e um endereço já suprimido manualmente retorna 200 OK com o registro existente em vez de um conflito. Em ambos os casos, o corpo é o objeto de supressão:
Exemplo de código
{
"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"
}
}O campo origin registra como o registro passou a existir. Adições manuais recebem api_key ou user, dependendo se o chamador se autenticou com uma chave API ou uma sessão do dashboard. Adições automáticas recebem bounce_event ou complaint_event, dependendo de qual sinal as criou.
Listar e consultar
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"A lista é paginada por cursor, do mais recente ao mais antigo, e filtrável por reason. Para verificar um endereço, passe-o como o parâmetro de consulta email:
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"Um array data vazio significa que o endereço não está suprimido, e vários registros são retornados quando mais de um motivo se aplica. O filtro email faz correspondência sem distinção de maiúsculas e minúsculas por prefixo, então um endereço completo retorna os registros daquele endereço e um fragmento como alice retorna todos os endereços suprimidos que começam com ele.
Remover um endereço
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"Retorna 204 No Content. A exclusão é permanente: não retemos nada, e o endereço volta a ser enviável. Excluir por endereço exige duas chamadas, uma consulta ?email= para obter o ID e depois a exclusão, e um endereço suprimido por vários motivos precisa que cada registro bloqueante seja excluído. Seja criterioso ao remover um registro hard_bounce, porque um endereço que ainda não existe retorna bounce no próximo envio e se suprime novamente.
O que acontece quando você envia para um endereço suprimido
Rejeitamos o destinatário onde você pode ver. O destinatário recebe um recipient_id e aparece na lista de destinatários da mensagem com status rejected. Os eventos API e seus webhooks registram um evento email.rejected com rejection_reason: "recipient_suppressed". Os demais destinatários são entregues normalmente.
A mensagem em si ainda é aceita com um 202, mesmo quando todos os seus destinatários estão suprimidos. Resolvemos a supressão após aceitar o envio, enquanto processamos a mensagem, então um endereço que você adicionar agora passa a valer em poucos minutos e nunca interrompe um envio já em andamento.
Testando com o sandbox
O sandbox de testes exercita o tratamento de supressão de forma determinística. Enviar para suppressed@messagebird.dev se comporta como se o endereço estivesse na sua lista: o destinatário é rejeitado com rejection_reason: "recipient_suppressed" e nunca chega à entrega. Os endereços de bounce e reclamação do sandbox (bounce@messagebird.dev, complaint@messagebird.dev) executam seus resultados pelo pipeline real de eventos sem gravar nada na sua lista de supressão, assim os mesmos endereços de teste continuam reutilizáveis entre execuções.
Próximos passos
- Categorias: transactional versus marketing, e como a categoria interage com a política de supressão
- Links de cancelamento de inscrição: como opt-outs registram uma preferência declarada em vez de uma supressão
- Eventos e webhooks: o payload email.rejected e os eventos de ciclo de vida que geram supressão automática
- Sandbox de testes: endereços mágicos para simular todos os resultados de entrega
- Referência API: Suppressions: esquemas completos de requisição e resposta
- O que acontece quando alguém cancela a subscrição: um vídeo que acompanha um destinatário desde a página de cancelamento de inscrição até um envio rejeitado
Recursos relacionados
Continue com a documentação, guias e exemplos sobre este tópico. Os recursos estão em inglês.
Entenda o conceitoWhat is one-click unsubscribe, and how do I implement List-Unsubscribe?Explore a funcionalidadeEmail opt-outsSiga o percurso de aprendizagemOperate messaging reliably
Obtenha um resumo de implementação