Store a subject and body once, publish it as an immutable version, then send it by slug. Liquid conditionals, loops, and filters run when the message is generated, so the personalization logic lives in the template instead of scattered through your code. Author it in the dashboard builder, from the bird CLI, or let an agent do it over MCP.
import { BirdClient } from "@messagebird/sdk";
import { render } from "@react-email/render";
import { WelcomeEmail } from "./emails/welcome";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.email.send({
from: "Bird <hello@bird.com>",
to: ["ada@example.com"],
subject: "Your invite is ready",
html: await render(<WelcomeEmail name="Ada" />),
}).safe();
if (error) throw error;
console.log(data.id);
// → "em_2bX91Yk8h..."
You can sign in any time at bird.com/login.
Your test API key is on your dashboard, ready to send.
存储一个模板。在发送时个性化。
The markup already lives in Bird.
Templates are part of the Bird Email API. Store the layout and its logic once; each send names the template by slug or id and passes the values its tokens need. The final message is rendered on our side, so the same template backs one receipt, a batch of a hundred, or a broadcast to a whole audience.
import { BirdClient } from "@messagebird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
// No subject and no html: the template's published version supplies both.
const { data, error } = await bird.email
.send({
from: "orders@acme.com",
to: ["delivered@messagebird.dev"],
category: "transactional",
template: {
slug: "order-confirmation",
parameters: {
first_name: "Ada",
order: { number: "A-1043", total: "$42.00" },
},
},
})
.safe();
不只是查找替换。
Liquid, resolved on Bird's side when the message is generated.
- 01
条件判断。
A Liquid if block shows only when its value applies, like a members-only note or a free-shipping banner, so one template covers both cases.
- 02
循环。
A for loop repeats a row for each item in an array, so one order-confirmation template lists every line item a customer actually bought. One limit worth knowing up front: a broadcast carries a single value per contact property and has nothing to iterate, so a template that loops sends through the messages API rather than a broadcast.
- 03
Filters.
Pipe a value through a Liquid filter before it renders. The default filter catches a missing first name before it ships as an empty greeting.
- 04
嵌套数据。
Dotted tokens reach into structured objects, so you can pass a whole order object and address its number and total from the markup instead of flattening it first.
- 05
Nothing to declare.
The token list is read off your markup, combined across every language, so there's no separate variable schema to keep in step with the body. Values can be any JSON: strings, numbers, booleans, arrays, objects.
用你既有的方式进行创作。
Three ways in, all reaching the same template. The dashboard builder is the visual one. The bird CLI drives the whole lifecycle from a script or a deploy step, and an agent reaches the same operations over MCP. Already have React Email components? Render them to HTML and store the result, leaving Bird's tokens as literal text in the JSX so they survive the render instead of baking in a value when React runs.
# Render React Email to HTML, then publish it as a template version.
node scripts/render-receipt.mjs > receipt.json
bird email templates create receipt --category transactional --source html
bird email templates versions languages set "$TEMPLATE" "$DRAFT" en \
--body-file receipt.json --yes
# --validate-only reports every problem across every language, freezing nothing.
bird email templates versions submit "$TEMPLATE" "$DRAFT" --validate-only --yes
bird email templates versions submit "$TEMPLATE" "$DRAFT" --yes
像你的其余代码一样带版本控制。
Editing happens on a draft and never touches what's live, because a send always resolves the current published version and drafts are never sent. Publishing freezes an immutable, numbered version and makes it live; if a change goes wrong, roll back to an earlier one. Saves carry the revision you last read, so if a teammate changed that language meanwhile the save is refused as a conflict rather than overwriting their work. Delivery and engagement stats break down per template, so you can see which one is actually landing.
One template, up to 25 languages.
A template carries content in up to 25 languages, each with its own subject and body, keyed by a BCP-47 tag like en or pt-BR. A send names the language it wants, or leaves it off and gets the template's default. When a send asks for a language the template doesn't carry, on_missing_language decides what happens: fallback serves the closest match, so a request for pt-BR is answered by a stocked pt, and fail rejects the send outright, for content where the wrong language is worse than no send at all.
精确预览将要发出的内容。
Fill a template with sample values and get back the subject and the HTML and text bodies a send would deliver. Preview renders the draft, which is how you check a change before it goes live, or a published version when you want to see what is going out right now. Nothing is sent. It also runs the same personalization checks as publishing, so a construct that would be rejected shows up here first.
模板的未来方向。
The visual builder and a starter library of forty built-in templates already ship, so you can copy one into your workspace and edit from there. Next on the list: describe a template in a prompt and get a draft to refine, a tighter compose surface for agents, and brand kits, which will hold your colors, type and voice at the workspace level and style a template from them. Each of those extends the same versioned model, so what you integrate today is what they build on.
在文档中深入了解。
The templates guide covers drafts, published versions, per-language content and the Liquid rules. The sending guide has the send-side contract, and email events and webhooks gets opens and clicks flowing back.
Templates ship with the platform around them.
在处理发送、送达率、抑制和分析的同一套 Email API 上存储、版本化并个性化模板。一套密钥。