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 nomes | Também | As leituras precisam de | As alterações precisam de |
|---|---|---|---|
| templates | template | templates:read | templates:write, e também emails:send para send |
| rules | rule | rules:read, incluindo test | rules:write |
| webhooks | webhook | webhooks:read | webhooks: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.
openemail templates --helpopenemail rules create --helpopenemail webhooks replay-delivery --help --jsonModelos
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.
| Comando | O que faz |
|---|---|
| openemail templates list | Listar 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-starters | Listar 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-fonts | Listar os tipos de letra web que um modelo pode carregar |
| openemail templates render | Renderizar 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.publishvolta 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 comtemplate_in_useenquanto 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_.
| Comando | O que faz |
|---|---|
| openemail rules list | Listar 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-runs | O 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,houreweekday. - Operadores:
matches,contains,equals,starts_with,ends_with,gtelt.gteltsó funcionam com os campos numéricos, ehas_attachmentespamsó aceitamequalscomtrueoufalse. - Tipos de ação:
label,remove_label,archive,mark_read,star,spam,trash,forward,reply,block_senderereject.labeleremove_labelaceitam um id de etiqueta comoUSER_RECEIPTS,forwardaceita um endereço ereplyaceita um id ou um slug de modelo. from_domaintambém corresponde aos subdomínios, ehoureweekdaysão lidos em UTC, com0para domingo.- Uma regra com uma ação
rejecttambém tem de testarenvelope_from, ou é recusada comreject_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_.
| Comando | O que faz |
|---|---|
| openemail webhooks list | Listar 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-deliveries | As 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-activity | O 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> --enabledrecupera-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 recebeowner_onlye o código de saída4.
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.
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-shippedEnviar 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.
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-runTestar 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.
[ { "field": "from_domain", "op": "equals", "value": "stripe.com" }, { "field": "has_attachment", "op": "equals", "value": "true" }][ { "type": "label", "value": "USER_RECEIPTS" }, { "type": "archive" }]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" --enabledLeia 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.
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.
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.jsonGuarde 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.
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--sincee--untilaceitam um instante ISO 8601.- Uma linha falhada cujo
nextAttemptAttem uma hora ainda tem uma nova tentativa automática por vir. replayRefusalénullquando um reenvio sairia, e caso contrário indica porque seria recusado, comowebhook_disabledenquanto 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
--jsonou--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ída4e não altera nada. Execute primeiroopenemail verify, e o perfil não precisa de código durante 60 minutos. --yesconfirma 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.
$ 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-runse cada comandowebhooks list…leem uma página de cada vez, de 25 linhas a menos que--limitpeça até 100. Um terminal mostra o--cursora passar para a página seguinte.--alllê todas as páginas,--max <n>para depois desse número de linhas, e--ndjsonmostra 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ída7. templates list-sendspagina por número, com--pagee--page-size, indica ototale não tem--all. Os números de página deslocam-se enquanto sai correio, por isso restrinja o período com--daysou--minutesem vez de paginar muito longe.templates list-startersetemplates list-fontsdevolvem o catálogo inteiro de uma vez, erules reorderdevolve cada regra como uma lista simples na nova ordem.- Uma caixa de correio tem no máximo 100 regras, por isso
rules list --limit 100devolve sempre todas as regras numa só página.
Opções que merecem um segundo olhar
--template-versioné o campoversiondo corpo, com outro nome porque--versionmostra a versão da CLI. O argumento<version>deget-version,restore-versionedelete-versioné um número de versão, não um idtplv_.--conditions,--actions,--document,--slots,--propse as outras opções JSON aceitam JSON em linha, de um ficheiro com@pathou de stdin com-.--dataaceita o corpo inteiro da mesma forma, e qualquer opção que também passe substitui a respetiva chave.--htmlaceita o próprio markup, não um ficheiro, por isso--html @page.htmlenvia o texto@page.html. Passe--html "$(cat page.html)", ou ponhahtmlno ficheiro que der a--data.rules update --conditionse--actionssubstituem a lista inteira, tal comowebhooks update --event-types,--address-allowliste--domain-allowlist. Leia o valor atual, altere-o e envie-o por inteiro.- Um
--event-typesvazio é 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-versionemtemplates update,replace-contenterestore-versionaceita a versão head que leu. Quando outra pessoa moveu a versão head entretanto, o comando para com o código de saída6eversion_conflict, e não escreve nada.rules update <id> --no-enableddesliga uma regra e mantém o seu lugar na ordem, que é a forma de pausar uma regra sem a eliminar.