# E-mail transacional > core.transactional-email — configuração protegida, templates versionados, preview, envio idempotente, fila com retentativas e painel administrativo. ## 1. Declare a capability ```json title="central.app.json" { "capabilities": ["core.transactional-email"], "capabilitySettings": { "core.transactional-email": { "enabled": true, "scopePolicy": "tenant_override", "retentionDays": 30, "attachmentsPolicy": { "allowed": false }, "templates": [ { "code": "confirmacao", "definition": "./backend/emails/confirmacao.json", "initialStatus": "active" } ] } } } ``` | Configuração | Valores | |---|---| | `scopePolicy` | `app_only`, `tenant_required` ou `tenant_override` | | `retentionDays` | 1 a 90 | | `attachmentsPolicy` | Anexos não são permitidos nesta linha | | `templates[].definition` | Caminho relativo ao manifesto, **dentro de `backend/`** para ir na imagem | ## 2. Crie o template ```json title="backend/emails/confirmacao.json" { "code": "confirmacao", "name": "Confirmação", "subject": "Olá, {{nome}}", "htmlContent": "
Olá, {{nome}}.
", "textContent": "Olá, {{nome}}.", "variablesSchema": { "type": "object", "additionalProperties": false, "required": ["nome"], "properties": { "nome": { "type": "string" } } }, "locale": "pt-BR", "initialStatus": "active", "attachmentsPolicy": { "allowed": false } } ``` Templates usam somente **interpolação Handlebars escapada**. Blocos, helpers, subexpressões, triple-stache e conteúdo remoto executável não são aceitos. O escape HTML vale só para `htmlContent`; assunto e texto saem literais (CR/LF são removidos do assunto). ## 3. Envie pelo backend ```javascript title="backend/src/services/confirmacao.js" const { capabilities } = require("@oondemand/oon-core-back"); async function enviarConfirmacao({ email, nome, idempotencyKey }, req) { return capabilities.transactionalEmail.send( { templateCode: "confirmacao", to: email, variables: { nome }, idempotencyKey, correlationId: req.correlationId, maxAttempts: 5, }, { ...req.accessContext, userId: req.accessContext?.userId }, ); } module.exports = { enviarConfirmacao }; ``` Retorno: `{ dispatchId, status, correlationId }` com `status` igual a `accepted` ou `duplicate`. > [!WARNING] > `idempotencyKey` é obrigatória e deve ser **estável** na repetição da mesma operação — não gere uma chave nova a cada retry. `accepted` indica aceite na fila, **não** entrega confirmada. O namespace `capabilities.transactionalEmail` também oferece preview e versionamento de templates, consulta de dispatches e retry de dead letter. ## 4. Painel administrativo ```tsx import { CoreTransactionalEmail } from "@oondemand/oon-core-front"; export function EmailPage() { return