Templates de e-mail
Um template é uma linha de assunto e um corpo de e-mail que você salva uma vez e envia várias vezes. Você escreve as partes que mudam como placeholders {{ variable }}, publica o template e então o envia pelo slug em vez de colar o mesmo HTML em cada chamada API. Um template pertence ao seu espaço de trabalho.
Crie e gerencie templates em Email > Templates, pelo /v1/email/templates, com o bird CLI ou pelo servidor MCP. Métodos tipados estão disponíveis nos SDKs de TypeScript, Python, PHP e Go em email.templates. Os schemas completos de solicitação e resposta estão na referência API. Envie um template publicado pelo endpoint de envio regular.
O que um template contém
Todo template tem dois nomes, e cada um cumpre uma função diferente:
slugé o nome pelo qual você envia o template, por exemplowelcome-email. Você o escolhe ao criar o template e não pode alterá-lo depois. Um slug pode conter letras minúsculas, números, hifens e underscores, precisa começar e terminar com uma letra ou número e pode ter até 63 caracteres. Dois prefixos são proibidos:bird_, que é reservado para os templates integrados, eemt_, que é o formato usado para IDs de template. O painel chama esse campo de Alias.nameé um rótulo de exibição em texto livre. O valor padrão é o slug, e você pode alterá-lo a qualquer momento. Nada é resolvido pelo nome, então renomear um template para exibição nunca interrompe um envio.
Além desses, um template tem um ID emt_ permanente, fixo por toda a sua vida. Ele também tem uma category, que pode ser marketing ou transactional, e uma source de autoria: html, markup finalizada que você fornece, opcionalmente personalizada com Liquid. A categoria e a origem são ambas fixas quando você cria o template.
Oferecemos um catálogo de templates integrados, e os slugs de todos começam com bird_. Um template integrado não pertence a nenhum espaço de trabalho, não pode ser editado e está sempre pronto para envio. Copie um para o seu espaço de trabalho para torná-lo seu, e ele se torna um template comum que você pode editar. A cópia chega como um rascunho não publicado que herda a categoria, a origem e as configurações de idioma do original, então publique-o antes de enviá-lo.
Rascunhos e versões publicadas
Todo template tem exatamente um rascunho, que é a cópia de trabalho que você edita. Ele também tem qualquer número de versões publicadas, cada uma numerada (1, 2, 3 e assim por diante) e nunca mais alterada depois de criada. Editar altera o rascunho no lugar. Publicar tira um snapshot do rascunho atual, transforma-o na próxima versão numerada e faz dessa versão a que os envios usam. O rascunho em si continua editável, então você pode seguir trabalhando no próximo.
A regra que importa para o envio é esta: um envio sempre usa a versão publicada do template, e um rascunho nunca é enviado sozinho. Você pode continuar editando o rascunho enquanto uma versão estável segue sendo enviada, e publicar quando a alteração estiver pronta. Publicar uma nova versão muda o que os envios seguintes renderizam. Um envio que já foi aceito não é afetado por uma publicação que aconteça depois.

Versões suportam mais duas ações. Descartar as alterações do rascunho para redefinir o rascunho de volta ao que está publicado no momento. Ou reverter para fazer uma versão publicada anterior voltar a ser a que os envios usam. Você só pode reverter para uma versão que foi publicada, nunca para o próprio rascunho. Reverter substitui o rascunho pelo conteúdo daquela versão, então qualquer coisa não salva no rascunho é perdida, e a edição continua a partir da versão para a qual você reverteu. Uma reversão não cria uma nova versão.
Para escolher uma imagem existente, você precisa de acesso de leitura à biblioteca de mídia do espaço de trabalho. Para fazer upload, colar ou soltar uma nova imagem, você precisa de acesso de escrita. Se Inserir imagem estiver desabilitado ou você não conseguir navegar ou fazer upload, peça a um administrador do espaço de trabalho a permissão correspondente da biblioteca de mídia. A permissão de edição de templates sozinha não concede acesso à biblioteca de mídia.
No dashboard, escolha Visual > Inserir imagem para pesquisar na sua biblioteca de mídia ou fazer upload de uma imagem PNG, JPEG, GIF ou WebP de até 5 MB. Uploads de WebP estático são convertidos para PNG ou JPEG. Selecione a imagem para definir sua Descrição da imagem, largura de exibição, alinhamento e link. Marque uma imagem como Imagem decorativa somente quando ela não adiciona informação; uma imagem com link precisa de uma descrição que explique seu destino. Cada idioma mantém suas próprias descrições de imagem e layout.
Use Substituir imagem para trocar uma imagem selecionada mantendo sua descrição, link, largura e alinhamento. Você também pode colar ou soltar um arquivo de imagem no editor visual. Aguarde o upload terminar, ou cancele-o, antes de salvar ou enviar um teste. Confira a pré-visualização, depois abra Mais ações > E-mail de teste para enviar o conteúdo atual para você mesmo. Código continua disponível para edição de HTML.
Remover uma imagem da biblioteca de mídia não a remove de e-mails já enviados. Substituir uma imagem usa uma nova URL, então mensagens anteriores continuam exibindo a original.
O salvamento é protegido por um número de revisão. Envie o revision que você leu por último para o idioma que está salvando. Se outra pessoa alterou aquele idioma nesse meio-tempo, o salvamento é recusado como conflito em vez de sobrescrever o trabalho dela. Omita revision para salvar incondicionalmente. A publicação e a reversão usam o revision do próprio rascunho da mesma forma.
Conteúdo em mais de um idioma
Um template armazena conteúdo em até 25 idiomas, cada um com seu próprio assunto e corpo, identificado por um código BCP-47 como en ou pt-BR. Um idioma é o padrão do template. Publicar um template publica todos os idiomas que ele contém ao mesmo tempo. Você não pode publicar um idioma sozinho, então todos precisam estar finalizados primeiro. Todo idioma precisa de um assunto e um corpo, e o idioma padrão do template precisa ser um dos idiomas que você preencheu. Se qualquer uma dessas condições não for atendida, nada é publicado, e o erro informa o que está faltando em cada idioma para que você possa corrigir tudo de uma vez. Você não precisa finalizar todos os idiomas de antemão: publique os que estiverem prontos e adicione o restante depois.
Um idioma precisa de um corpo HTML. Você pode omitir seu text: a publicação então cria uma alternativa em texto puro a partir do HTML automaticamente, então você obtém as duas partes sem precisar escrever a segunda.
Cada idioma também pode ter um texto de pré-visualização, às vezes chamado de preheader: a linha que a caixa de entrada mostra depois do assunto na lista de mensagens. É opcional, tem até 255 caracteres e aceita os mesmos placeholders {{ variable }} que o assunto. Se você não incluir, a caixa de entrada usa a primeira linha do corpo, que raramente é a linha que você escolheria. A publicação recusa texto de pré-visualização em um idioma cujo corpo não tem parte HTML, já que um cliente de e-mail só lê a linha de pré-visualização a partir de marcação HTML oculta, e recusa {{ bird.unsubscribe_url }} dentro dele pelo mesmo motivo que o assunto não pode contê-lo: nenhum dos dois é um lugar onde um link pode ir.
Duas configurações cobrem um envio que não nomeia um idioma para o qual o template tem conteúdo, e elas protegem contra erros diferentes:
| Configuração | O que controla |
|---|---|
on_missing_language | O que acontece quando um envio pede um idioma que o template não tem. fallback, o padrão, serve a correspondência mais próxima. Primeiro tenta uma forma mais ampla do mesmo idioma, então um pt armazenado pode atender uma solicitação para pt-BR. Em seguida, recorre ao idioma padrão do template. fail rejeita o envio, para conteúdo em que enviar no idioma errado é pior do que não enviar. |
language_source_required | Se um envio precisa nomear um idioma. Está desativado por padrão, então um envio que não nomeia nenhum recebe o idioma padrão. Ative, e esse envio é rejeitado. Um broadcast nomeia um idioma para toda a sua audiência, então um template com essa configuração ativada precisa que o idioma seja escolhido antes que o broadcast possa enviar. |
Você pode definir essas duas configurações de forma independente. Sozinho, fail só se aplica quando um envio nomeia um idioma que não temos, então um envio que não nomeia nenhum ainda passa. Ative ambas as configurações juntas quando quiser que cada envio nomeie um idioma de propósito.
Personalizando com variáveis
Escreva placeholders {{ variable }} no assunto, no texto de pré-visualização e no corpo. Nós os detectamos automaticamente, combinados entre todos os idiomas, então você nunca precisa declará-los separadamente. O prefixo do placeholder distingue os dois tipos. Um caminho que começa com bird. lê dos nossos dados, seja um registro de contato ou o link de cancelamento de inscrição. Todo o resto é um parâmetro para o qual você fornece um valor ao enviar.
O nome de um parâmetro é uma palavra única, como {{ animal }}. Um nome com pontos tenta acessar uma estrutura que um parâmetro não tem, então publicar um assim é rejeitado: escreva o valor como seu próprio parâmetro, ou leia dados de contato com bird.contact.<attribute>.
Em um envio único ou em lote, o valor de um parâmetro vem do objeto template.parameters do envio, identificado pelo nome. Um único conjunto de valores cobre todos os destinatários desse envio. bird é o único nome que você não pode usar ali: uma chave template.parameters chamada bird é rejeitada com um 422.
Um broadcast não tem objeto parameters, então seu conteúdo só pode usar placeholders bird.. bird.contact.<attribute> é preenchido a partir das propriedades de contato de cada destinatário, que é o que personaliza o conteúdo por destinatário. Toda propriedade de contato fica disponível pela própria chave, assim como os três campos nativos: first_name, last_name e email.
Hi {{ bird.contact.first_name }},Todo parâmetro no template precisa de um valor no momento do envio. Caso contrário, o API retorna um 422 que indica o parâmetro ausente. Forneça valores para os parâmetros em todos os idiomas, porque o idioma selecionado pode depender das configurações de fallback. Uma propriedade de contato ausente é renderizada como valor vazio, então adicione um fallback para conteúdo visível ao cliente: {{ bird.contact.first_name | default: "there" }}.
Um broadcast é mais restrito quanto aos nomes que aceita, porque propriedades de contato são tudo o que ele tem para preencher placeholders. Seus placeholders bird.contact.* só podem nomear um campo nativo ou uma propriedade de contato que o espaço de trabalho tenha registrado. Qualquer outro placeholder, incluindo um parâmetro, é algo que o broadcast não tem como preencher. O envio é recusado, e o erro indica o placeholder.
Arquivar uma propriedade remove-a do seletor de propriedades no editor. Novas versões de template que a referenciam não podem ser publicadas, e o erro indica a propriedade. Templates já publicados continuam enviando. Desarquive a propriedade para usá-la em novas versões novamente.
Placeholders usam Liquid, então filtros e fluxo de controle funcionam junto com substituição simples. Um condicional {% if %} e um loop {% for %} sobre um valor de array são perfeitamente válidos. Alguns construtos são rejeitados quando você publica, e o erro indica exatamente o que mudar:
- Inclusões parciais, usando
{% include %}ou{% render %}. - As tags
increment,decrementeifchanged. - Os filtros
money,format_date,format_time,json,inspectetype. - Comparações com
emptyoublank. Use.size == 0em vez disso. - Blocos aninhados muito mais fundo do que a marcação de e-mail real precisa.
O template de um broadcast não pode usar um loop {% for %} de forma alguma, porque um broadcast preenche um único valor por propriedade de contato e não tem nada sobre o que iterar. Se seu conteúdo precisa de um loop, envie-o pela API de mensagens.
Todo template usa Liquid, inclusive um que contém apenas placeholders {{ variable }}. Antes de publicar, validamos o assunto, o texto de pré-visualização, o HTML e o conteúdo em texto simples como Liquid. Também adicionamos o filtro escape a cada saída HTML que ainda não termine com escape ou escape_once, para que um valor contendo & ou < não altere a marcação ao redor. A saída reservada de cancelamento de inscrição permanece inalterada para que o envio possa substituí-la. O assunto e o corpo em texto simples são mantidos como escritos. Como a publicação adiciona esses filtros, o HTML que você lê de uma versão publicada pode não ser idêntico byte a byte ao que você enviou.
Coloque uma URL completa diretamente em um href, como <a href="{{ sign_in_url }}">Sign in</a>. Não adicione url_encode ao valor inteiro. Ele codifica em porcentagem https://, /, ? e &, o que impede o resultado de funcionar como um link absoluto. Nós adicionamos escape de HTML preservando a estrutura da URL. Quando um parâmetro fornece um componente da URL, codifique esse componente explicitamente: <a href="https://example.com/search?q={{ query | url_encode }}">Search</a>.
Pré-visualizando antes de publicar
Renderize um template com valores de exemplo e receba de volta o assunto e os corpos em HTML e texto simples que um envio entregaria. A pré-visualização usa nosso renderizador Liquid local e renderiza o rascunho por padrão, que é como você confere uma alteração antes de ela entrar em produção. Ela também pode renderizar uma versão publicada. Funciona para seus próprios templates e para os nossos templates integrados, e nada é enviado.
Você também pode fornecer o conteúdo diretamente em vez de deixar a leitura do rascunho por conta do sistema. Passe um assunto e os corpos, e eles serão renderizados exatamente como um rascunho seria, o que permite que um editor mostre uma alteração conforme ela é digitada sem salvar nada antes.
A personalização é preenchida automaticamente, então o que retorna aparece como texto final em vez de placeholders {{ }}. Informe um contact e cada bird.contact.<attribute> é resolvido a partir das propriedades desse contato, que é como você confere sua redação contra um registro real antes que alguém o receba. Os valores vêm da mesma projeção que um broadcast usa para preencher seus placeholders, então a pré-visualização responde com o que um envio responderia.
Omita contact e valores substitutos serão usados: Bird e Test para o primeiro e o último nome, bird.test@example.com para o e-mail, e o fallback registrado de cada outra propriedade. Uma propriedade referenciada sem fallback é renderizada como sua chave entre colchetes, como [loyalty_tier], o que indica tanto que o valor é um placeholder quanto qual propriedade ainda precisa de um fallback.
Um contato é lido como está neste momento. Isso faz da pré-visualização a ferramenta certa para conferir o conteúdo que você está prestes a enviar, e a ferramenta errada para perguntar o que um envio anterior continha. Para ler o que um envio realmente entregou, abra essa mensagem no log de e-mail, que a renderiza a partir dos valores que aquele envio carregou.
Adicione language para renderizar um idioma específico, ou omita para usar o padrão do template. A resposta informa qual idioma foi renderizado, o que importa quando o idioma solicitado não está disponível e o on_missing_language do template serviu uma correspondência próxima.
Se o rascunho tiver personalização que seria rejeitada ao publicar, a pré-visualização retorna o mesmo erro, então ela também serve para encontrar problemas antecipadamente.
No construtor de templates do dashboard, Preview with contact data na parte inferior do painel esquerdo mostra o e-mail renderizado ao lado do que você está editando, tanto no editor visual quanto no editor de código. O seletor abaixo escolhe de quem são os dados que preenchem os placeholders, e Sample data são os valores substitutos descritos acima.
Enviando com um template
Defina o campo template do envio como um objeto que nomeia o template, seja por id (emt_...) ou por slug, usando exatamente um dos dois. Coloque os valores das variáveis em template.parameters. Adicione language para escolher um idioma específico, ou omita para enviar no idioma padrão do template, a menos que o template exija que cada envio nomeie um. Omita subject, html e text completamente, porque o template já os fornece.
{
"from": "hello@yourdomain.com",
"to": ["delivered@messagebird.dev"],
"category": "transactional",
"template": {
"slug": "welcome-email",
"parameters": { "first_name": "Jane" }
}
}Um comportamento que vale planejar: a categoria do template é um padrão, e o category do próprio envio a sobrescreve. Omita category, e o envio herda a categoria do template, então um template operacional envia como transacional sem você repetir isso a cada chamada. Defina category, e o seu valor prevalece. O restante do contrato do lado do envio está em envio com template.
Criação fora do dashboard
Todo o ciclo de vida está disponível fora do dashboard: pela API, pelos SDKs em email.templates, pelo bird CLI e pelas ferramentas email_templates_* MCP. Nos SDKs, as operações de versão e idioma ficam em email.templates.versions e email.templates.versions.languages. A etapa de publicação se chama submit lá, e transforma o rascunho na próxima versão publicada.
Você pode manter templates no seu próprio repositório e sincronizá-los a partir de uma etapa de build. Um rascunho e uma versão publicada retornam HTML diferente, então escolha a leitura que corresponde ao que a sua ferramenta precisa:
- Um rascunho retorna exatamente como você salvou. O HTML que você salva em um idioma do rascunho volta byte a byte da leitura daquele idioma (
GET /v1/email/templates/{id}/versions/{draft_version_id}/languages/{language}) e da leitura de versão, incluindo o doctype, blocos<style>, comentários, espaços em branco, quebras de linha e texto não ASCII. Um salvamento não retorna conteúdo, então leia o idioma de volta quando precisar confirmar o que foi armazenado. - Uma versão publicada retorna pronta para envio. A publicação reescreve o HTML de três formas: cada saída
{{ }}que ainda não termina comescapeouescape_onceganha o filtroescape, exceto{{ bird.unsubscribe_url }}, que permanece como escrito; o texto de pré-visualização é inserido em um bloco oculto logo após a tag de abertura<body>, ou no início quando o HTML não tem nenhuma; e umtextvazio é preenchido com uma alternativa em texto simples derivada do HTML. A leitura dessa versão retorna o conteúdo reescrito, então não vai corresponder ao seu arquivo fonte.
Para exportar o código-fonte que você criou, leia o rascunho. Ler um template ou listar templates retorna metadados e estado por idioma, mas nenhum HTML.
Os exemplos abaixo usam {{ first_name }}, que é um parâmetro: o envio fornece seu valor em template.parameters, como em "parameters": {"first_name": "Jane"}. Isso serve para um envio a um endereço de e-mail. Um placeholder {{ bird.contact.first_name }} lê o registro de contato do destinatário, que um broadcast preenche a partir das propriedades de contato de cada destinatário. Um envio a um endereço de e-mail não tem registro de contato, então recusa um template que lê bird.contact.* com um 422 (EmailTemplateContactUnavailable).
Crie o template com seu primeiro idioma. A resposta traz o id do template e o draft_version_id, que as operações de versão e idioma recebem. O exemplo também define preview_text, o texto de pré-visualização que a caixa de entrada mostra após o assunto na lista de mensagens. A publicação o insere no HTML como um bloco oculto, o que é uma das razões pelas quais uma versão publicada retorna HTML diferente do rascunho:
const template = await bird.email.templates.create({
slug: "welcome-email",
category: "transactional",
source: "html",
languages: {
en: {
subject: "Welcome, {{ first_name }}",
preview_text: "Your account is ready",
html: "<!DOCTYPE html>\n<html>\n<body>\n<p>Hi {{ first_name }}, thanks for signing up.</p>\n</body>\n</html>\n",
},
},
});
console.log(template.id, template.draft_version_id);template = client.email.templates.create(
slug="welcome-email",
category="transactional",
source="html",
languages={
"en": {
"subject": "Welcome, {{ first_name }}",
"preview_text": "Your account is ready",
"html": "<!DOCTYPE html>\n<html>\n<body>\n<p>Hi {{ first_name }}, thanks for signing up.</p>\n</body>\n</html>\n",
},
},
)
print(template.id, template.draft_version_id)template, err := client.Email.Templates.Create(context.Background(), bird.EmailTemplatesCreateParams{
Slug: "welcome-email",
Category: "transactional",
Source: "html",
Languages: map[string]bird.EmailTemplateLanguageContent{
"en": {
Subject: bird.String("Welcome, {{ first_name }}"),
PreviewText: bird.String("Your account is ready"),
Html: bird.String("<!DOCTYPE html>\n<html>\n<body>\n<p>Hi {{ first_name }}, thanks for signing up.</p>\n</body>\n</html>\n"),
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(template.Id, *template.DraftVersionId)$template = $bird->email->templates->create(
slug: 'welcome-email',
category: 'transactional',
source: 'html',
languages: [
'en' => [
'subject' => 'Welcome, {{ first_name }}',
'preview_text' => 'Your account is ready',
'html' => "<!DOCTYPE html>\n<html>\n<body>\n<p>Hi {{ first_name }}, thanks for signing up.</p>\n</body>\n</html>\n",
],
],
);
echo $template->getId(), ' ', $template->getDraftVersionId();bird email templates create --body-file - <<'EOF'
{
"slug": "welcome-email",
"category": "transactional",
"source": "html",
"languages": {
"en": {
"subject": "Welcome, {{ first_name }}",
"preview_text": "Your account is ready",
"html": "<!DOCTYPE html>\n<html>\n<body>\n<p>Hi {{ first_name }}, thanks for signing up.</p>\n</body>\n</html>\n"
}
}
}
EOFcurl -X POST https://us1.platform.bird.com/v1/email/templates \
-H "Authorization: Bearer bk_us1_..." \
-H "Content-Type: application/json" \
-d '{
"slug": "welcome-email",
"category": "transactional",
"source": "html",
"languages": {
"en": {
"subject": "Welcome, {{ first_name }}",
"preview_text": "Your account is ready",
"html": "<!DOCTYPE html>\n<html>\n<body>\n<p>Hi {{ first_name }}, thanks for signing up.</p>\n</body>\n</html>\n"
}
}
}'Para alterar um idioma depois, salve-o novamente com bird email templates versions languages set ou um PUT no mesmo caminho de idioma. O corpo é plano: subject, que é obrigatório, mais preview_text, html e text. Um campo que você omitir é limpo. Adicione o revision que você leu por último para recusar o salvamento se outra pessoa alterou aquele idioma nesse meio-tempo.
O layout do editor visual do dashboard é um dos campos limpos dessa forma, porque a API, os SDKs e o CLI não conseguem enviá-lo. Salvar um idioma que você construiu no editor visual mantém o HTML, mas remove o layout, então o dashboard reabre aquele idioma no editor de código.
Os próximos passos usam TEMPLATE_ID e DRAFT_VERSION_ID para o id e o draft_version_id que a chamada de criação retornou. Leia o idioma do rascunho de volta para obter o HTML exatamente como está armazenado:
const language = await bird.email.templates.versions.languages.get(
"TEMPLATE_ID",
"DRAFT_VERSION_ID",
"en",
);
console.log(language.content?.html);language = client.email.templates.versions.languages.get(
"TEMPLATE_ID",
"DRAFT_VERSION_ID",
"en",
)
if language.content is not None:
print(language.content.html)language, err := client.Email.Templates.Versions.Languages.Get(context.Background(),
"TEMPLATE_ID", "DRAFT_VERSION_ID", "en")
if err != nil {
log.Fatal(err)
}
if language.Content != nil && language.Content.Html != nil {
fmt.Println(*language.Content.Html)
}$language = $bird->email->templates->versions->languages->get(
'TEMPLATE_ID',
'DRAFT_VERSION_ID',
'en',
);
echo $language->getContent()?->getHtml();bird email templates versions languages get "$TEMPLATE_ID" "$DRAFT_VERSION_ID" en \
| jq -j .content.html > welcome-email.htmlcurl "https://us1.platform.bird.com/v1/email/templates/$TEMPLATE_ID/versions/$DRAFT_VERSION_ID/languages/en" \
-H "Authorization: Bearer bk_us1_..." \
| jq -j .content.html > welcome-email.htmljq -j grava a string sem adicionar uma quebra de linha no final, então o arquivo contém os mesmos bytes que a API armazenou.
Envie o rascunho com validate_only primeiro. Ele executa as mesmas verificações de um envio real em todos os idiomas e reporta os problemas encontrados em uma única resposta, sem publicar nada. Depois envie sem validate_only para publicar a próxima versão, que os envios passam a usar:
const templateId = "TEMPLATE_ID";
const draftVersionId = "DRAFT_VERSION_ID";
const check = await bird.email.templates.versions.submit(templateId, draftVersionId, {
validate_only: true,
});
for (const problem of check.errors) {
console.log(problem.language, problem.field, problem.message);
}
if (check.valid) {
const result = await bird.email.templates.versions.submit(templateId, draftVersionId);
console.log(result.version?.version_number);
}template_id = "TEMPLATE_ID"
draft_version_id = "DRAFT_VERSION_ID"
check = client.email.templates.versions.submit(template_id, draft_version_id, validate_only=True)
for problem in check.errors:
print(problem.language, problem.field, problem.message)
if check.valid:
result = client.email.templates.versions.submit(template_id, draft_version_id)
if result.version is not None:
print(result.version.version_number)ctx := context.Background()
templateID := "TEMPLATE_ID"
draftVersionID := "DRAFT_VERSION_ID"
check, err := client.Email.Templates.Versions.Submit(ctx, templateID, draftVersionID,
bird.EmailTemplatesVersionsSubmitParams{ValidateOnly: bird.Bool(true)})
if err != nil {
log.Fatal(err)
}
if check.Errors != nil {
for _, problem := range *check.Errors {
fmt.Println(*problem.Message)
}
}
if check.Valid != nil && *check.Valid {
result, err := client.Email.Templates.Versions.Submit(ctx, templateID, draftVersionID,
bird.EmailTemplatesVersionsSubmitParams{})
if err != nil {
log.Fatal(err)
}
fmt.Println(*result.Version.VersionNumber)
}$templateId = 'TEMPLATE_ID';
$draftVersionId = 'DRAFT_VERSION_ID';
$check = $bird->email->templates->versions->submit(
$templateId,
$draftVersionId,
(new EmailTemplateSubmit())->setValidateOnly(true),
);
foreach ($check->getErrors() ?? [] as $problem) {
echo $problem->getLanguage(), ' ', $problem->getField(), ' ', $problem->getMessage(), "\n";
}
if ($check->getValid() === true) {
$result = $bird->email->templates->versions->submit($templateId, $draftVersionId, new EmailTemplateSubmit());
echo $result->getVersion()?->getVersionNumber();
}bird email templates versions submit "$TEMPLATE_ID" "$DRAFT_VERSION_ID" --validate-only
bird email templates versions submit "$TEMPLATE_ID" "$DRAFT_VERSION_ID"curl -X POST "https://us1.platform.bird.com/v1/email/templates/$TEMPLATE_ID/versions/$DRAFT_VERSION_ID/submit" \
-H "Authorization: Bearer bk_us1_..." \
-H "Content-Type: application/json" \
-d '{"validate_only": true}'
curl -X POST "https://us1.platform.bird.com/v1/email/templates/$TEMPLATE_ID/versions/$DRAFT_VERSION_ID/submit" \
-H "Authorization: Bearer bk_us1_..." \
-H "Content-Type: application/json" \
-d '{}'O corpo do envio aceita validate_only e expected_revision. Passe o revision do template como expected_revision para recusar a publicação caso o rascunho tenha mudado desde a última leitura.
Liste os templates do seu espaço de trabalho para encontrar o slug que um envio referencia:
for await (const tpl of bird.email.templates.list({ scope: "workspace" })) {
console.log(tpl.slug, tpl.name);
}for template in client.email.templates.list(scope="workspace"):
print(template.slug, template.name)for tpl, err := range client.Email.Templates.List(context.Background(), bird.EmailTemplatesListParams{Scope: "workspace"}) {
if err != nil {
log.Fatal(err)
}
fmt.Println(*tpl.Slug, tpl.Name)
}foreach ($bird->email->templates->list(['scope' => 'workspace']) as $template) {
echo $template->getSlug(), ' ', $template->getName(), "\n";
}bird email templates list --scope workspacecurl "https://us1.platform.bird.com/v1/email/templates?scope=workspace" \
-H "Authorization: Bearer bk_us1_..."Envie o template publicado pelo slug, com um valor em template.parameters para cada parâmetro que ele usa, aqui first_name:
const msg = await bird.email.send({
from: { email: "onboarding@messagebird.dev", name: "Bird" },
to: ["delivered@messagebird.dev"],
category: "transactional",
template: {
slug: "welcome-email",
parameters: { first_name: "Jane" },
},
});
console.log(msg.id, msg.status);msg = client.email.send(
from_={"email": "onboarding@messagebird.dev", "name": "Bird"},
to=["delivered@messagebird.dev"],
category="transactional",
template="welcome-email",
parameters={"first_name": "Jane"},
)
print(msg.id, msg.status)msg, err := client.Email.Send(context.Background(), bird.EmailSendParams{
From: "onboarding@messagebird.dev",
To: []string{"delivered@messagebird.dev"},
Category: "transactional",
Template: "welcome-email",
Parameters: map[string]any{"first_name": "Jane"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)$message = $bird->email->send(
from: 'Bird <onboarding@messagebird.dev>',
to: ['delivered@messagebird.dev'],
category: 'transactional',
template: (new EmailMessageSendRequestTemplate())
->setSlug('welcome-email')
->setParameters(['first_name' => 'Jane']),
);
echo $message->getId(), ' ', $message->getStatus();bird email send \
--category transactional \
--from hello@yourdomain.com \
--parameters '{"first_name":"Jane"}' \
--template welcome-email \
--to delivered@messagebird.devcurl -X POST https://us1.platform.bird.com/v1/email/messages \
-H "Authorization: Bearer bk_us1_..." \
-H "Content-Type: application/json" \
-d '{
"from": "hello@yourdomain.com",
"to": ["delivered@messagebird.dev"],
"category": "transactional",
"template": {
"slug": "welcome-email",
"parameters": { "first_name": "Jane" }
}
}'Próximos passos
- Enviando e-mail: o payload completo de envio e como envios com template se encaixam nele
- Categorias: escolhendo
marketingvstransactionalem cada envio bird email templates: gerenciando templates pelo terminal- Referência do API: schemas completos de solicitação e resposta para todas as dezoito operações de template
- SDKs: os métodos tipados de
email.templatesem TypeScript, Python, PHP e Go - MCP server: permitir que um agente crie e publique templates
- Como criar um template de email: um vídeo que cria um template no dashboard e depois faz um agente criar outro
Recursos relacionados
Continue com a documentação, guias e exemplos sobre este tópico.