Sign inGet Started

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 exemplo welcome-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, e emt_, 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.

A aba Versões do template com uma linha de Rascunho e linhas das versões publicadas v3, v2 e v1 mostrando suas datas de criação e publicação

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 Insert image 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 > Insert image para pesquisar na sua biblioteca de mídia ou fazer upload de uma imagem PNG, JPEG, GIF ou WebP estática dentro dos limites de upload da biblioteca de mídia. Uploads de WebP estático são convertidos para PNG ou JPEG. Selecione a imagem para definir sua Image description, largura de exibição, alinhamento e link. Marque uma imagem como Decorative image 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çãoO que controla
on_missing_languageO 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_requiredSe 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

Envios de template individuais, em lote e agendados podem usar valores de contato. Cada endereço To precisa corresponder a um contato quando o template lê bird.contact.*.

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.

Use bird.contact.<attribute> para ler as propriedades de contato do destinatário, incluindo os campos nativos first_name, last_name e email. Envios individuais e em lote associam cada endereço To a um contato do mesmo espaço de trabalho. Destinatários em Cc e Bcc recebem uma cópia do e-mail personalizado de cada destinatário To e não precisam de contatos correspondentes. Um broadcast lê os contatos da sua audiência e também aceita valores do chamador nos parâmetros do template.

Exemplo de código
Hi {{ bird.contact.first_name }},

Forneça os parâmetros obrigatórios do chamador usados pelo idioma resolvido. Um parâmetro obrigatório ausente retorna 422. Um valor obrigatório nulo também retorna 422; uma string vazia intencional continua válida. A lista variables da versão cobre todos os seus idiomas, então um parâmetro usado apenas por outro idioma não precisa de valor neste envio.

A publicação registra os atributos de contato usados por cada idioma. O envio busca apenas os atributos usados pelo idioma selecionado e pelos campos do envio. Um envio sem referências a contatos não faz a consulta de contato.

Um template que lê bird.contact.* exige um contato correspondente no espaço de trabalho para cada destinatário To. Se um destinatário To não tiver contato, a solicitação retorna 422 com E04099 antes de aceitar qualquer mensagem, inclusive em lotes ou envios agendados. Primeiro crie ou atualize o contato, ou use parâmetros do chamador. Um filtro default ou uma condição Liquid não elimina esse requisito. Templates que usam parâmetros do chamador ou bird.unsubscribe_url sem atributos de contato não precisam de um contato correspondente.

Por exemplo, envie Hello {{ bird.contact.first_name }} para Alice e Bob, com Charlie em Cc:

EntregaSaudaçãoTo visível
AliceHello AliceAlice
Charlie, em cópia no e-mail de AliceHello AliceAlice
BobHello BobBob
Charlie, em cópia no e-mail de BobHello BobBob

Charlie recebe duas cópias, então essa solicitação gera quatro entregas. Bcc funciona da mesma forma, com o endereço Bcc oculto. Esses e-mails personalizados separados se aplicam quando o template usa atributos de contato; envios comuns mantêm o comportamento de endereçamento existente. A mesma regra vale para cada mensagem do lote API.

Um contato existente pode ter o nome ou sobrenome vazio. Nomes ausentes são exibidos como valores vazios, e você escolhe a saudação no modelo. Para uma saudação com o primeiro nome, use Hello {{ bird.contact.first_name | default: "there" }}!. Para o nome completo, combine as duas partes, remova os espaços das extremidades e escolha um valor padrão:

Exemplo de código
{% assign full_name = bird.contact.first_name | append: " " | append: bird.contact.last_name | strip %}
Hello {{ full_name | default: "there" }}!

Isso exibe Hello Jane Doe!, Hello Jane! ou Hello Doe! quando os nomes correspondentes estão presentes, e Hello there! quando ambos estão ausentes. Não é necessário definir nomes substitutos para todo o workspace.

As propriedades de contato que você cria mantêm os valores alternativos configurados. Um null armazenado conta como ausente; uma string explicitamente vazia, false ou zero continua sendo um valor. Uma propriedade ausente sem valor alternativo é exibida vazia. Propriedades desconhecidas e valores armazenados inválidos impedem a aceitação. Uma consulta que falhou permite tentar novamente e não substitui os dados por valores alternativos.

Um placeholder bird.contact.* precisa nomear um atributo nativo ou uma propriedade personalizada registrada. Os nomes de parâmetros do chamador continuam separados desses caminhos da plataforma. Envios de template individuais e em lote salvam os valores do destinatário no momento da aceitação, inclusive em envios agendados, e os reutilizam em novas tentativas de entrega e em leituras da mensagem. Broadcasts mantêm seu próprio momento de preparação. Envios individuais e em lote rejeitam entradas sensíveis antes da aceitação.

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, decrement e ifchanged.
  • Os filtros money, format_date, format_time, json, inspect e type.
  • Comparações com empty ou blank. Use .size == 0 em vez disso.
  • Blocos aninhados muito mais fundo do que a marcação de e-mail real precisa.

Parâmetros de template em broadcasts aceitam valores escalares; arrays e objetos não são suportados. Sem parâmetros do chamador, tanto {% for %} quanto {% tablerow %} aceitam intervalos literais como (1..3) e listas criadas no Liquid com split. Um broadcast que usa parâmetros do chamador aceita {% for %} sobre uma lista criada com split, mas rejeita intervalos e {% tablerow %}. Em ambos os casos, uma tag de loop que lê diretamente um parâmetro do chamador ou uma propriedade do contato é rejeitada, incluindo intervalos cujo limite lê um desses valores.

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. Por isso, a pré-visualização é a ferramenta certa para conferir o conteúdo que você está prestes a enviar, mas não serve para descobrir o que um envio anterior continha. Para ver 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.

Exemplo de código
{
  "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 com escape ou escape_once ganha o filtro escape, 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 um text vazio é preenchido com uma alternativa em texto simples derivada do HTML. A leitura dessa versão retorna o conteúdo reescrito, então ele difere do 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 }}, um parâmetro do chamador fornecido em template.parameters, como em "parameters": {"first_name": "Jane"}. Use {{ bird.contact.first_name }} quando o template precisar ler o contato do destinatário no espaço de trabalho. Enderece os destinatários por e-mail tanto em envios individuais quanto em lote. A estilização salva no template publicado continua fazendo parte daquela versão. Não existe namespace bird.brandkit.* em tempo de execução.

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);

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);

jq -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.

Faça o submit do rascunho com validate_only primeiro. Ele executa as mesmas verificações de um submit real em todos os idiomas e reporta os problemas encontrados em uma única resposta, sem publicar nada. Depois faça o submit 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);
}

O corpo do submit 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);
}

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);

Próximos passos

  • Enviando e-mail: o payload completo de envio e como envios com template se encaixam nele
  • Categorias: escolhendo marketing vs transactional em 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.templates em TypeScript, Python, PHP e Go
  • Servidor MCP: 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

Continue com a documentação, guias e exemplos sobre este tópico.