Saltar para a documentação
CLI

Modelos, regras e webhooks

Cada comando de `templates`, `rules` e `webhooks`: corpos guardados que envia por slug, regras que arquivam o correio que chega e eventos assinados para o seu próprio servidor.

Três espaços de nomes

Estes três espaços de nomes permitem que uma caixa de correio funcione sem ninguém a vigiar. templates guarda corpos que envia muitas vezes, rules arquiva o correio à medida que chega e webhooks diz ao seu próprio servidor o que aconteceu. Cada comando é um método do SDK com o nome em kebab-case, por isso webhooks.rotateSecret é openemail webhooks rotate-secret, e lê argumentos e opções como qualquer outro comando de recurso.

Espaço de nomesTambémAs leituras precisam deAs alterações precisam de
templatestemplatetemplates:readtemplates:write, e também emails:send para send
rulesrulerules:read, incluindo testrules:write
webhookswebhookwebhooks:readwebhooks:write, incluindo test e replay-delivery

Esta página lista cada comando e o que convém saber antes de o usar num script. Para cada argumento e opção, com o tipo, os scopes de que precisa, o endpoint e o que devolve, execute openemail <namespace> <verb> --help. Acrescente --json para ter a mesma página como JSON.

Ajuda
openemail templates --helpopenemail rules create --helpopenemail webhooks replay-delivery --help --json

Modelos

Corpos guardados uma vez e enviados muitas, com versões, pré-visualizações e props tipadas. Cada comando que aceita <id-or-slug> admite o id tpl_ ou o slug. O slug nunca muda quando o modelo muda de nome, por isso fixe o slug nos scripts.

ComandoO que faz
openemail templates listListar modelos, primeiro os atualizados mais recentemente. --status mantém os de rascunho, ativos ou arquivados, --search pesquisa nomes, slugs e assuntos, e --sort escolhe a ordem
openemail templates get <id-or-slug>Ler um modelo com a sua versão head completa, corpo incluído
openemail templates create --name <value>Criar um modelo e a sua primeira versão. Fica como rascunho a menos que passe --publish, e --starter inicia-o a partir de um design inicial
openemail templates update <id-or-slug>Editar o nome, o slug, a descrição ou o estado, ou o corpo do rascunho. Os envios mantêm a versão publicada até publicar
openemail templates duplicate <id-or-slug>Copiar a versão head para um modelo novo, que começa como rascunho
openemail templates replace-content <id-or-slug>Substituir o corpo pelo de um design inicial (--starter) ou pelo de outro modelo (--from-template-id). Pede-lhe confirmação
openemail templates delete <id-or-slug>Eliminar um modelo e todas as suas versões. Pede-lhe confirmação
openemail templates list-versions <id-or-slug>Listar as versões, da mais recente para a mais antiga, sem os corpos
openemail templates get-version <id-or-slug> <version>Ler uma versão com o corpo, sem tocar no rascunho
openemail templates publish <id-or-slug>Publicar o rascunho para que os envios o usem. Publicar uma versão head que já está publicada não altera nada
openemail templates restore-version <id-or-slug> <version>Recuperar o corpo de uma versão anterior como rascunho. Pede-lhe confirmação
openemail templates delete-version <id-or-slug> <version>Eliminar uma versão. A versão publicada, a versão head e a única versão são recusadas. Pede-lhe confirmação
openemail templates list-startersListar os designs iniciais incluídos
openemail templates get-starter <slug>Ler um design inicial completo, com a sua árvore de blocos e uma pré-visualização renderizada
openemail templates list-fontsListar os tipos de letra web que um modelo pode carregar
openemail templates renderRenderizar um corpo que não está guardado em lado nenhum, a partir de --html ou --document
openemail templates preview <id-or-slug>Renderizar um modelo guardado com --props e --slots, rascunhos incluídos, sem o enviar
openemail templates get-analytics <id-or-slug>Envios, aberturas e cliques num período, por dia, por origem e por versão
openemail templates list-sends <id-or-slug>As mensagens individuais que o modelo enviou, da mais recente para a mais antiga, uma página de cada vez
openemail templates send <id-or-slug> --from <value> --to <a,b>Enviar um email renderizado a partir da versão publicada, ou daquela que --template-version fixa

Um modelo tem uma versão head, que é um rascunho enquanto tiver edições por publicar, e uma versão publicada, que é a que um envio sem --template-version usa. create sem --publish, uma edição do corpo com update, replace-content e restore-version escrevem todos no rascunho, por isso os destinatários não veem nada de novo até publish.

  • Um modelo arquivado recusa-se a enviar com template_archived. publish volta a ativá-lo.
  • Um espaço de trabalho tem no máximo 200 modelos, incluindo os arquivados, por isso eliminar é a única forma de fazer espaço.
  • delete é recusado com template_in_use enquanto uma difusão agendada ou em fila ainda indicar o modelo.

Regras

Condições e ações avaliadas sobre o correio que chega, pela ordem que rules list mostra. Uma regra só atua sobre o correio que chega enquanto está ativa. Nenhum comando aplica uma regra ao correio que já está na caixa de correio, e rules test é a forma de ver o que apanharia. Os ids de regra começam por rul_.

ComandoO que faz
openemail rules listListar as regras pela ordem em que são executadas. --enabled ou --no-enabled mantém um só tipo
openemail rules get <id>Ler uma regra, com matchCount e lastMatchedAt
openemail rules create --name <value> --conditions <json|@file|-> --actions <json|@file|->Criar uma regra no fim da ordem. Fica ativa a menos que passe --no-enabled
openemail rules update <id>Alterar uma regra. --conditions e --actions substituem a lista inteira, e --position move só esta regra
openemail rules delete <id>Eliminar uma regra. O que já fez fica em list-runs. Pede-lhe confirmação
openemail rules reorder <rule-ids...>Definir a ordem de todas as regras de uma vez, indicando cada regra exatamente uma vez
openemail rules test <id>Testar uma regra em simulação contra o correio que já está na caixa de correio. Não altera nada e funciona com uma regra desativada
openemail rules list-runsO que as regras fizeram realmente ao correio que chegou, do mais recente para o mais antigo. --rule-id e --thread-id filtram-no

--conditions é uma lista de objetos { field, op, value }, unidos por --match all ou --match any, onde value é sempre uma cadeia e negate: true inverte uma condição. --actions é uma lista de objetos { type, value }, aplicados por ordem. Uma regra admite de 1 a 20 condições e de 1 a 10 ações, e uma caixa de correio tem no máximo 100 regras.

  • Campos de condição: from, from_domain, envelope_from, to, cc, bcc, recipient, reply_to, delivered_to, subject, body, header, list_id, attachment_name, attachment_type, has_attachment, attachment_size, message_size, spam, hour e weekday.
  • Operadores: matches, contains, equals, starts_with, ends_with, gt e lt. gt e lt só funcionam com os campos numéricos, e has_attachment e spam só aceitam equals com true ou false.
  • Tipos de ação: label, remove_label, archive, mark_read, star, spam, trash, forward, reply, block_sender e reject. label e remove_label aceitam um id de etiqueta como USER_RECEIPTS, forward aceita um endereço e reply aceita um id ou um slug de modelo.
  • from_domain também corresponde aos subdomínios, e hour e weekday são lidos em UTC, com 0 para domingo.
  • Uma regra com uma ação reject também tem de testar envelope_from, ou é recusada com reject_needs_envelope.

Webhooks

Endpoints no seu próprio servidor que recebem eventos assinados da caixa de correio, com os segredos de assinatura, o registo de entregas e um registo de auditoria de cada alteração. Os ids de endpoint começam por whe_ e os ids de entrega por whd_.

ComandoO que faz
openemail webhooks listListar os endpoints do espaço de trabalho, do mais recente para o mais antigo, com o respetivo estado
openemail webhooks get <id>Ler um endpoint. O segredo de assinatura nunca faz parte de uma leitura
openemail webhooks create --url <value>Registar um endpoint HTTPS. Mostra o segredo de assinatura, a única vez que vê esse segredo
openemail webhooks update <id>Alterar o URL, os eventos, as listas de permissões ou se está ativo. Cada lista substitui a guardada
openemail webhooks delete <id>Eliminar um endpoint e o seu registo de entregas. Pede-lhe confirmação
openemail webhooks rotate-secret <id>Emitir um segredo de assinatura novo. O anterior deixa de funcionar de imediato. Pede-lhe confirmação
openemail webhooks test <id>Enviar um evento sintético assinado email.sent e indicar como correu a entrega
openemail webhooks list-deliveries <id>As tentativas de entrega de um endpoint, da mais recente para a mais antiga. --status, --since e --until filtram-nas
openemail webhooks get-delivery <id> <delivery-id>Uma tentativa completa: o corpo enviado, a resposta do seu servidor, cada tentativa do evento e se um reenvio seria aceite
openemail webhooks replay-delivery <id> <delivery-id>Voltar a enviar agora para o endpoint um evento guardado
openemail webhooks list-workspace-deliveriesAs tentativas de entrega de todos os endpoints, ou dos que --endpoint-ids indica
openemail webhooks list-activity <id>O registo de auditoria de um endpoint: quem o criou, alterou, testou, reenviou ou removeu
openemail webhooks list-workspace-activityO registo de auditoria de todos os endpoints, incluindo os removidos

Se omitir --event-types, um endpoint recebe o conjunto predefinido, os eventos email.* exceto email.replied. email.replied, os eventos domain.* e os eventos suppression.* só lhe chegam quando os indicar. --address-allowlist e --domain-allowlist limitam um endpoint a alguns endereços ou domínios, tal como limitam uma chave de API.

  • Um espaço de trabalho tem 10 endpoints, a menos que o suporte tenha aumentado o limite.
  • Um endpoint que falha 100 entregas seguidas é desligado pelo servidor, e webhooks update <id> --enabled recupera-o.
  • Com um início de sessão no navegador, só o proprietário do espaço de trabalho pode ler uma entrega com get-delivery. Qualquer outra pessoa recebe owner_only e o código de saída 4.

Verificar um modelo e depois publicá-lo

templates preview renderiza exatamente o que um envio com os mesmos valores produziria, rascunhos incluídos, e só precisa de templates:read, por isso até uma chave só de leitura o pode executar. Indica uma prop obrigatória em falta como aviso onde send a recusaria, por isso faça falhar o build perante qualquer aviso. publish é seguro em cada implementação, porque publicar uma versão head que já está publicada não altera nada.

CI
draft=$(openemail templates get order-shipped --json | jq .latestVersion)openemail templates preview order-shipped --template-version "$draft" \  --props '{"orderId":"AC-4192","customer":"Ada"}' --json | jq -e '.warnings == []'openemail templates publish order-shipped

Enviar a partir de um modelo

Fixe a versão, para que uma reescrita publicada amanhã não altere o que este código envia, e passe uma chave de idempotência tirada daquilo que causou o envio, para que uma nova tentativa depois de perder a resposta reproduza a primeira mensagem em vez de enviar uma segunda. --dry-run mostra o método, o URL, os cabeçalhos com a sua credencial ocultada e o corpo, não envia nada e sai com o código 0. Execute-o de novo sem --dry-run para enviar.

Terminal
openemail templates send order-shipped \  --from 'Acme <[email protected]>' \  --to [email protected] \  --template-version 5 \  --props '{"orderId":"AC-4192","customer":"Ada"}' \  --idempotency-key order-shipped:AC-4192 \  --dry-run

Testar uma regra antes de ser executada

Crie a regra desligada, teste-a em simulação contra o correio recente e ligue-a quando apanhar o que pretendia. Com um início de sessão no navegador, rules create e rules update pedem um código de verificação, que um script não consegue escrever, por isso execute primeiro openemail verify. Durante os 60 minutos seguintes esse perfil executa-os sem perguntar.

conditions.json
[  { "field": "from_domain", "op": "equals", "value": "stripe.com" },  { "field": "has_attachment", "op": "equals", "value": "true" }]
actions.json
[  { "type": "label", "value": "USER_RECEIPTS" },  { "type": "archive" }]
Terminal
openemail verifyrule=$(openemail rules create --name 'Stripe receipts' \  --conditions @conditions.json --actions @actions.json --no-enabled --json | jq -r .id)openemail rules test "$rule" --days 30 --limit 100openemail rules update "$rule" --enabled

Leia os avisos de rules test antes das correspondências. field_unevaluable significa que uma condição lê algo que o correio guardado já não tem, por isso o teste não a conseguiu avaliar, e forward_unverified significa que um destino de reencaminhamento não está alojado aqui. wouldApply lista o que a regra declara: um reencaminhamento para um endereço que não confirmou continua a falhar quando chega correio real.

Pôr uma regra em primeiro lugar e ver porque é que uma mensagem se moveu

rules reorder aceita cada regra da caixa de correio exatamente uma vez. Uma regra omitida ou indicada duas vezes é recusada e nada se move. rules list devolve os ids pela ordem em que são executadas, por isso ponha a que quer em primeiro lugar à frente das restantes.

Terminal
first=rul_4f1c9a2b7d3e8f6a0b5c1d2eopenemail rules reorder "$first" $(openemail rules list --all --ndjson \  | jq -r --arg first "$first" 'select(.id != $first) | .id')openemail rules list-runs --thread-id CAHk7pQ2x9LmZ4 --json | jq '.items[] | {ruleName, actions, failures}'

list-runs é o registo do que aconteceu realmente. Cada linha é uma regra que correspondeu a uma mensagem, com as ações que tiveram efeito e, em failures, as que a caixa de correio recusou, como uma resposta a um remetente já respondido nesse dia. Cada linha mantém o nome que a regra tinha nesse momento, por isso --rule-id funciona com uma regra que entretanto eliminou.

Registar um webhook e provar que funciona

webhooks create mostra o segredo de assinatura uma vez, e nenhum comando posterior o volta a mostrar. Com --json vai no JSON em stdout, enquanto o lembrete para o guardar vai para stderr, por isso a saída continua a poder ser analisada. webhooks test envia um evento sintético assinado email.sent seja qual for a subscrição do endpoint, e nenhum email é enviado.

Terminal
openemail verifyopenemail webhooks create --url https://hooks.acme.com/openemail \  --event-types email.received,email.bounced,email.complained \  --description 'Support desk sync' --json > endpoint.jsonjq -r .secret endpoint.jsonopenemail webhooks test "$(jq -r .id endpoint.json)" --json | jq .deliveryrm endpoint.json

Guarde o segredo no seu cofre de segredos antes de eliminar o ficheiro. test sai com o código 0 mesmo quando o seu servidor falha, por isso leia delivery.status: delivered para uma resposta 2xx e failed para qualquer outra, incluindo um redirecionamento, já que os redirecionamentos nunca são seguidos. Um responseCode de null significa que não chegou resposta nenhuma.

Encontrar entregas falhadas e voltar a enviar uma

Depois de uma falha do seu lado, liste o que falhou em todos os endpoints, verifique que um reenvio seria aceite e volte a enviar o evento. Um reenvio leva o mesmo id de evento, por isso um recetor que descarta ids que já tratou trata-o como o evento que já conhece.

Terminal
openemail webhooks list-workspace-deliveries --status failed --since 2026-09-26T00:00:00Z --all --ndjson \  | jq -r '[.endpointId, .id, .eventType, (.responseCode // "no answer")] | @tsv'openemail webhooks get-delivery whe_3f9c2a7b1e4d8f60a5c7b92d whd_8c1e4a7f2b9d3e6a0c5f1b28 --json | jq .replayRefusalopenemail webhooks replay-delivery whe_3f9c2a7b1e4d8f60a5c7b92d whd_8c1e4a7f2b9d3e6a0c5f1b28
  • --since e --until aceitam um instante ISO 8601.
  • Uma linha falhada cujo nextAttemptAt tem uma hora ainda tem uma nova tentativa automática por vir.
  • replayRefusal é null quando um reenvio sairia, e caso contrário indica porque seria recusado, como webhook_disabled enquanto o endpoint está desligado.
  • Os reenvios são feitos um evento de cada vez. Nenhum comando volta a enviar todas as entregas falhadas.

Códigos de verificação

Com um início de sessão no navegador, quatro destes comandos pedem um código de verificação antes de alterar o que quer que seja, como faz a aplicação web: rules create, rules update, webhooks create e webhooks update. A uma chave de API nunca é pedido. Todos os outros comandos desta página são executados sem código, incluindo as eliminações e webhooks rotate-secret.

  • Num terminal, a CLI envia-lhe por email um código de seis dígitos, ou pede um da sua aplicação de autenticação quando o início de sessão em dois passos está ativo, e depois executa o comando uma vez.
  • Sem supervisão, com --json ou --no-input, em CI ou sem terminal, ninguém pode escrever o código, por isso o comando para com o código de saída 4 e não altera nada. Execute primeiro openemail verify, e o perfil não precisa de código durante 60 minutos.
  • --yes confirma uma eliminação, mas nunca salta um código.

Confirmações e simulações

Sete comandos desta página removem ou substituem alguma coisa, por isso pedem-lhe primeiro confirmação: templates delete, templates delete-version, templates replace-content, templates restore-version, rules delete, webhooks delete e webhooks rotate-secret. Sem supervisão, cada um para com o código de saída 2, a menos que passe --yes.

Terminal
$ openemail webhooks delete whe_3f9c2a7b1e4d8f60a5c7b92d --no-input✗ Refusing to run unattended. Pass --yes to confirm.$ openemail webhooks delete whe_3f9c2a7b1e4d8f60a5c7b92d --yes

--dry-run mostra o primeiro pedido que alteraria alguma coisa e sai com o código 0, sem o enviar nem lhe pedir confirmação. Com --json mostra um único documento { dryRun, request }. rules test, templates render e templates preview não alteram nada, mas são pedidos POST, por isso uma simulação mostra-os em vez de os executar.

Paginação

  • templates list, templates list-versions, rules list, rules list-runs e cada comando webhooks list… leem uma página de cada vez, de 25 linhas a menos que --limit peça até 100. Um terminal mostra o --cursor a passar para a página seguinte.
  • --all lê todas as páginas, --max <n> para depois desse número de linhas, e --ndjson mostra um objeto JSON por linha. Com --json, uma lista mostra um único documento { items, hasMore, nextCursor }, também com --all.
  • Devolva um cursor com os mesmos filtros e a mesma ordenação com que veio. Qualquer outra coisa é recusada como invalid_cursor, com o código de saída 7.
  • templates list-sends pagina por número, com --page e --page-size, indica o total e não tem --all. Os números de página deslocam-se enquanto sai correio, por isso restrinja o período com --days ou --minutes em vez de paginar muito longe.
  • templates list-starters e templates list-fonts devolvem o catálogo inteiro de uma vez, e rules reorder devolve cada regra como uma lista simples na nova ordem.
  • Uma caixa de correio tem no máximo 100 regras, por isso rules list --limit 100 devolve sempre todas as regras numa só página.

Opções que merecem um segundo olhar

  • --template-version é o campo version do corpo, com outro nome porque --version mostra a versão da CLI. O argumento <version> de get-version, restore-version e delete-version é um número de versão, não um id tplv_.
  • --conditions, --actions, --document, --slots, --props e as outras opções JSON aceitam JSON em linha, de um ficheiro com @path ou de stdin com -. --data aceita o corpo inteiro da mesma forma, e qualquer opção que também passe substitui a respetiva chave.
  • --html aceita o próprio markup, não um ficheiro, por isso --html @page.html envia o texto @page.html. Passe --html "$(cat page.html)", ou ponha html no ficheiro que der a --data.
  • rules update --conditions e --actions substituem a lista inteira, tal como webhooks update --event-types, --address-allowlist e --domain-allowlist. Leia o valor atual, altere-o e envie-o por inteiro.
  • Um --event-types vazio é um erro de utilização. Para voltar a pôr um endpoint no conjunto predefinido, envie --data '{"eventTypes":[]}', e para parar as suas entregas, passe --no-enabled.
  • --expected-version em templates update, replace-content e restore-version aceita a versão head que leu. Quando outra pessoa moveu a versão head entretanto, o comando para com o código de saída 6 e version_conflict, e não escreve nada.
  • rules update <id> --no-enabled desliga uma regra e mantém o seu lugar na ordem, que é a forma de pausar uma regra sem a eliminar.

A sua caixa de entrada,
nos seus termos.

Infraestrutura de email para empresas, IA, agentes e correio pessoal. Feita para escala, privacidade e controlo. Tudo o que o email devia ter tido desde o primeiro dia.

OpenEmail

Infraestrutura de email para empresas, IA, agentes e correio pessoal. Feita para escala, privacidade e controlo. Tudo o que o email devia ter tido desde o primeiro dia.

© 2026 OpenEmail. Todos os direitos reservados.