Sign inGet started

从 Mailjet 迁移

本页将 Mailjet 的 Send API v3.1 载荷、屏蔽列表和 Event API 映射到 Bird。按顺序参照主迁移指南,并在步骤 1、3 和 4 中使用这些映射。
最大的结构变化在于请求封装。Mailjet 将每次发送包裹在一个由 PascalCase 对象组成的 Messages 数组中(POST /v3.1/send)。我们为每个 POST /v1/email/messages 接收一个扁平的小写 JSON 对象,多条独立消息应发送到批量端点,而非使用 Messages 数组。

交给你的 agent

将本页粘贴到 Claude Code、Cursor 或 Codex 中。Agent 会基于你的代码仓库逐步执行本页内容,使用它已有的任何 Bird 接口:已连接的 MCP 服务器,或者已安装并登录的 CLI。
代码示例
I am moving an email integration from Mailjet to Bird. Route through it with me.
1. Check what you already have before setting anything up. If Bird's MCP server is connected, use its tools. If the Bird CLI is installed and signed in, use that. Either one is enough, and every step below is an action you take with whichever you have. Only if neither is present, follow https://bird.com/docs/ai/set-up-your-agent.md to set one up and sign me in. Every Bird docs page serves Markdown at its own URL with `.md` appended, so fetch that rather than the HTML.
2. Read https://bird.com/docs/guides/email/migrate/mailjet.md for the payload, suppression and event mapping, and https://bird.com/docs/guides/email/migrate.md for the order the steps go in.
3. Find and list my Mailjet usage in this repository before you change anything: the POST /v3.1/send call sites and any SDK wrappers around them, the event handler and the URL it is registered at, and every domain I send from.
4. Register each of those sending domains with Bird and give me the DNS records to publish, following https://bird.com/docs/guides/email/sending-domains.md. Leave every DNS record my current provider uses exactly as it is: Bird's records are published alongside them and both providers authenticate side by side until I switch traffic. Publishing DNS affects mail for the whole domain, so show me the records and let me publish them.
5. Export my blocklist from Mailjet and import it into Bird before any production traffic goes through Bird, so my first sends do not reach addresses that already bounced or complained. Read it through the contact-management API, or from the contact statistics pages if that is what I have access to. The Bird import takes one address per request and is idempotent, so a partial re-run is safe. https://bird.com/docs/guides/email/suppressions.md has the reason taxonomy.
6. Port the send call and the event handler using the mapping tables on the provider page. Mailjet posts a Messages array of PascalCase objects, and each entry becomes either one flat Bird send or one entry in a batch, so tell me which shape my call sites map onto before you rewrite them. EventPayload becomes metadata. Bird signs deliveries per Standard Webhooks rather than Mailjet's scheme, so treat verification as a rewrite rather than a URL change: https://bird.com/docs/guides/webhooks.md and https://bird.com/docs/guides/email/events.md.
7. Run my whole integration against Bird's mail sandbox before any production traffic, following https://bird.com/docs/guides/email/testing-sandbox.md. Sandbox sends run the real pipeline without reaching an inbox or touching my sending reputation.
8. Stop and ask me wherever a step needs a decision. Do not point production traffic at Bird until I have seen the sandbox results and replied with the words cut over to Bird. Retiring the Mailjet path is a separate step that comes later: ask me again and wait for me to reply with the words retire the Mailjet path. A reply that agrees without naming what it is authorising is not authorisation. Finish by telling me what is left that only a person can do.

映射发送调用

功能Mailjet(Send API v3.1)Bird
发件人From: { "Email", "Name" }from: string 或 { "email", "name" }
收件人To / Cc / Bcc: [{ "Email", "Name" }]to / cc / bcc: arrays
主题Subjectsubject
正文TextPart / HTMLParttext / html(至少一个)
回复地址ReplyTo: { "Email", "Name" }reply_to: array
自定义请求头Headersheaders: string → string object
往返上下文EventPayload(string),在事件中回传metadata: 任意 JSON
自定义发送 IDCustomID,在事件中回传metadatatags
存储模板TemplateID + Variablestemplate + template.parameters
附件Attachments: { "ContentType", "Filename", "Base64Content" }attachments: { "content_type", "filename", "content" }
内联图片InlinedAttachments,带有 ContentIDattachments 带有 content_id
跟踪账户/模板设置track_opens / track_clicks(默认 true
分类(无)category: marketing(默认)或 transactional
字段上限和默认值(收件人数量、标签和元数据限制)详见发送邮件
迁移注意事项:
  • 解开 Messages 数组。 Mailjet 的单次发送是 Messages 中的一个条目。在这里,它就是整个请求体。包含多个条目的 Messages 数组映射到我们的批量端点。单个请求中的重复字段无法表示批量发送。
  • 大小写从 PascalCase 变为 lowercase。 每个字段都要重命名:HTMLParthtmlTextParttextFrom.Emailfrom.email。这是机械操作,但涉及每一次发送。
  • EventPayload 变为 metadata Mailjet 在每个事件中回传一个 EventPayload 字符串。我们在每个 webhook 事件中回传结构化的 metadata(JSON)和 tags,因此你可以将关联数据拆分为有类型的字段。参见标签与元数据
  • CustomID 是关联标识,重试需要另行处理。 Mailjet 的 CustomID 会传递到事件中用于追踪,但不做去重。它们的去重依赖 X-Mailjet-DeduplicateCampaign,一个与 X-Mailjet-Campaign 搭配使用的布尔值,用于阻止同一活动重复发送给同一收件人,这是活动级别的保证,而非单次请求的安全重试。在这里,将你的关联 ID 放入 metadatatags,并使用 Idempotency-Key 请求头来确保重试请求的安全性。
  • 存储模板可直接迁移。 Mailjet 的 TemplateID + Variables 映射到我们的 template 字段(通过 ID 或 slug 引用),变量值放在 template.parameters 中。参见使用模板发送。超出变量替换的模板逻辑也可迁移:Mailjet 的 TemplateLanguage 条件和循环在我们的模板中变为 Liquid 的 {% if %}{% for %}
  • 附件可直接迁移。 Mailjet 的 Base64Content 对应我们的 base64 contentInlinedAttachments + ContentID 变为带有 content_idattachments 条目。参见附件

导出屏蔽列表

Mailjet 将无法送达和不需要的地址保存在其屏蔽列表中(硬退回/软退回和被阻止的发送),并单独追踪垃圾邮件投诉和退订信号。从 Mailjet 的联系人统计页面导出被阻止和被退回的地址,或通过联系人管理 API拉取,然后通过导入流程处理该列表。如果你发送营销邮件,还应迁移标记为已退订的联系人,以确保这些偏好设置在迁移后保留。

转换 webhook 事件

Mailjet 的 Event API 为每种事件类型发送一个触发。以下是到我们事件词汇表的映射:
结果MailjetBird
已接受/已处理(无)email.acceptedemail.processed
已投递sentemail.delivered
永久退回bounceemail.bounced / email.out_of_band_bounce
已阻止blockedemail.rejected
垃圾邮件投诉spamemail.complained
打开openemail.opened
点击clickemail.clicked
退订unsubemail.unsubscribed / email.list_unsubscribed
需要在代码中处理的两个差异:
  • 我们会明确上报投递前的各个阶段。 Mailjet 的 sent 在收件方邮件服务器接收消息后触发,对应我们的 email.delivered。我们还会在此之前发出 email.acceptedemail.processed,让你在投递确认之前就能看到发送进度。不要将这些早期事件视为已投递。
  • 事件以收件人为粒度。 Mailjet 通过 MessageID 标识事件。我们的投递事件包含 recipient_idemail_id,因此多收件人发送会为每个收件人生成独立的事件流。我们按照 Standard Webhooks 规范对投递事件签名。验证方式参见 Webhooks 与事件

正式切换

按照主指南完成域名与 DNS沙箱冒烟测试。两者与服务商无关。

后续步骤

  • 发送域名:注册、验证生命周期,以及你需要重新指向的 DNS 记录
  • Webhooks 与事件:端点配置和 Standard Webhooks 验证
  • 测试沙箱:在正式切换前对新集成进行冒烟测试
  • 屏蔽列表:确认导入的列表以及后续的维护方式