屏蔽列表
您的工作区拥有一个屏蔽列表:一组我们不会向其投递邮件的电子邮件地址。硬退信和垃圾邮件投诉会自动进入该列表,您也可以手动添加地址。反复向退信或举报垃圾邮件的地址发送邮件可能导致您的域名被邮箱服务商封锁,因此我们会在邮件离开平台之前阻止这些发送。
退订不在此列表中。它记录的是收件人自己表达的偏好,而非投递能力方面的事实,因此位于 Preferences 标签页下。请参阅退订链接了解其工作方式。
您可以在 Email > Suppressions 中管理列表,也可以通过屏蔽列表 API 或 bird email suppressions 来管理。

三种原因及其屏蔽范围
| 原因 | applies_to | 营销类别 | 事务类别 |
|---|---|---|---|
| hard_bounce | all | 已屏蔽 | 已屏蔽 |
| complaint | non_transactional | 已屏蔽 | 已放行 |
| manual | all | 已屏蔽 | 已屏蔽 |
这种区分源于每种原因的含义:
- hard_bounce:该地址不存在。向任何类别发送都毫无意义,因此屏蔽所有类别。
- complaint:关于不想接收邮件的声明。将您的新闻邮件举报为垃圾邮件的人可能仍然需要密码重置或订单确认,因此仅屏蔽非事务性发送。
- manual:您或您的团队做出的刻意决定。我们不会质疑这一决定,因此手动屏蔽会阻止所有类别,包括事务性邮件。
一个地址每种原因持有一条记录,因此硬退信和之前的投诉会作为独立记录并存,只要任何屏蔽记录存在,投递就保持被阻止状态。对于无法识别的内容,我们默认关闭:如果返回的记录中包含您的集成从未见过的 applies_to,请将其视为屏蔽所有类别,这也是我们自己的处理方式。
Note: reason: unsubscribe is deprecated on the suppressions API. Unsubscribes now record a preference instead of a suppression, so ?reason=unsubscribe matches nothing.
地址如何被自动添加
我们根据收件人信号添加屏蔽记录,因此退信或投诉无需您采取任何操作:
| 触发条件 | 产生的屏蔽记录 |
|---|---|
| 硬退信(email.bounced) | reason: hard_bounce、origin: bounce_event、applies_to: all |
| 带外硬退信(email.out_of_band_bounce) | reason: hard_bounce、origin: bounce_event、applies_to: all |
| 垃圾邮件投诉(email.complained) | reason: complaint、origin: complaint_event、applies_to: non_transactional |
退订操作不会出现在此列表中,无论是通过邮件正文中的链接还是一键按钮:它会在 Preferences 标签页中记录偏好,而不是向此列表添加一行。
只有 hard 级别的退信会触发屏蔽,分类表展示了哪些 bounce_class 值属于硬退信。两种看似失败的结果不会屏蔽该地址:
- 软退信和延迟投递(email.deferred,或带有 bounce_type: "soft" 的 email.bounced):如邮箱已满等临时性故障。我们会重试。
- 发送端拒绝:生成失败和策略拒绝是发送本身的问题,而非地址的问题。它们产生 email.rejected 事件,不会创建屏蔽记录。
对于已因相同原因被屏蔽的地址,重复信号不会更改原始记录,包括其 created_at。该记录保留 source_email_id 和 source_recipient_id,它们将自动屏蔽关联回引起屏蔽的确切消息和收件人。这两个字段可以回答支持问题 "why did this person stop getting our email",在手动添加的记录中它们为 null。
每次添加(无论自动还是手动)都会向您的 webhook 端点触发一个 email_suppression.created 事件,包含 suppression_id、被屏蔽的 email、reason 和 workspace_id,这样您的系统可以镜像该列表而无需轮询:
代码示例
{
"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"
}
}通过 API 管理屏蔽列表
API 可添加、列出、查找和删除单条记录。地址在存储和查找之前会被转为小写,且永远不会出现在 URL 路径中,因为路径会记录在访问日志中,而电子邮件地址属于个人数据。要查找某个地址的记录,请使用 ?email= 过滤列表。
SDK 示例通过每个客户端的原始请求方法访问屏蔽列表,该方法与类型化调用共享相同的认证、重试和基础 URL 处理。响应结构由您自行声明。
添加地址
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" }'在 CLI 上,bird email suppressions 涵盖 list 和 remove;添加地址通过 API 完成。
手动添加的记录获得 reason: manual 和 applies_to: all,因此会屏蔽所有类别。该调用是幂等的:新屏蔽记录返回 201 Created,已被手动屏蔽的地址返回 200 OK 及现有记录,而非冲突。两种情况下响应体均为屏蔽对象:
代码示例
{
"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"
}
}origin 字段记录该记录的创建方式。手动添加的记录值为 api_key 或 user,取决于调用者是通过 API 密钥还是仪表板会话进行认证。自动添加的记录值为 bounce_event 或 complaint_event,取决于触发它们的信号类型。
列出和查找
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"列表使用游标分页,按最新排序,可通过 reason 过滤。要检查单个地址,将其作为 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"空的 data 数组表示该地址未被屏蔽,当多个原因同时适用时会返回多条记录。email 过滤器按前缀进行不区分大小写的匹配,因此完整地址返回该地址的记录,而类似 alice 的片段则返回以其开头的所有被屏蔽地址。
移除地址
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"返回 204 No Content。删除是永久性的:我们不保留任何内容,该地址重新变为可发送状态。按地址删除需要两次调用:先通过 ?email= 查找 ID,然后执行删除;因多个原因被屏蔽的地址需要逐条删除每个屏蔽记录。移除 hard_bounce 记录时请务必谨慎,因为仍然不存在的地址会在下次发送时退信并重新自动屏蔽。
向被屏蔽的地址发送时会发生什么
我们会在您可见的位置拒绝该收件人。收件人会收到 recipient_id,并以状态 rejected 出现在消息的收件人列表中。事件 API 和您的 webhook 记录一个带有 rejection_reason: "recipient_suppressed" 的 email.rejected 事件。其余收件人正常投递。
消息本身仍然以 202 被接受,即使所有收件人都被屏蔽也是如此。我们在接受发送后、处理消息时解析屏蔽状态,因此您现在添加的地址会在几分钟内生效,且不会阻止已在投递中的发送。
使用沙盒测试
测试沙盒以确定性方式测试屏蔽处理。向 suppressed@messagebird.dev 发送邮件的行为与该地址在您的列表中时相同:收件人以 rejection_reason: "recipient_suppressed" 被拒绝,永远不会进入投递流程。沙盒的退信和投诉地址(bounce@messagebird.dev、complaint@messagebird.dev)通过真实事件管道执行其结果,但不会向您的屏蔽列表写入任何内容,因此相同的测试地址在多次运行中保持可复用。
后续步骤
- 类别:transactional 与 marketing 的对比,以及类别如何与屏蔽策略交互
- 退订链接:退出操作如何记录为表达的偏好而非屏蔽
- 事件和 webhook:email.rejected 载荷及驱动自动屏蔽的生命周期事件
- 测试沙盒:用于模拟每种投递结果的魔法地址
- API 参考:屏蔽列表:完整的请求和响应结构
- 当有人选择退订时会发生什么:一段视频,跟踪一位收件人从退订页面到发送被拒绝的完整过程