Inbox
Uma Inbox é um endereço de e-mail roteável com uma política de processamento. Cada inbox pertence a um workspace e pode associar um único agente para processamento automatizado.
Propósito
- Prover um endereço único para um caso de uso (triagem de suporte, intake de faturas, revisão de contratos, etc.).
- Definir filtros que decidem se um e-mail de entrada é
approvedourejected. - Controlar política de anexos (quantidade, tamanho por arquivo, tamanho total).
- Opcionalmente rotear todo e-mail aprovado para um
Agentpara processamento por LLM.
Importante: provisionamento só no banco
Criar uma inbox não chama a AWS. O SES inbound trabalha por domínio — com a Domain Identity verificada e o MX apontado, todo endereço *@inbox.{env}.kobana.com.br chega ao SES independente de existir no banco. O registro de inbox é o que torna o endereço roteável adiante; sem ele o e-mail é descartado em process-email com rejection_reason=recipient_unknown.
Schema
| Campo | Tipo | Descrição |
|---|---|---|
id | UUID | ID interno. |
external_id | UUID | ID estável do sistema de origem. Unique. |
workspace_id | UUID | Workspace dono. |
agent_id | UUID | null | Agent opcional para e-mails aprovados. |
label | string | Label humano. |
email | string | O endereço roteável. Globalmente único. |
status | enum | active ou inactive. |
allowed_recipients | string[] | Quando não-vazio, somente e-mails cujo to contém um destes endereços são aprovados. Wildcards (*@acme.com) suportados. |
filters | JSON | Array de regras de filtro (veja abaixo). |
attachments_allow | bool | Se anexos são permitidos. |
attachments_max_file_number | int | Máx de anexos por e-mail. Default 10. |
attachments_max_file_size | int | Bytes. Default 10485760 (10 MiB). |
attachments_max_total_size | int | Bytes. Default 41943040 (40 MiB). |
attachments_allow_rules | array|null | Lista de anexos permitidos. null processa todos os anexos. Ver Regras de anexos permitidos. |
custom_metadata | object | Free-form. |
metadata | object | Controlado pelo sistema. |
created_at / updated_at / deleted_at | datetime |
Filtros
O campo filters é um array JSON. Cada elemento é uma regra como:
{ "field": "from", "op": "matches", "value": "^.*@acme\\.com$" }
field | op | value |
|---|---|---|
from, subject, header.<name> | equals, contains, matches (regex) | string |
headers.list-id | present, absent | (sem value) |
body.text | contains | string |
Regras são AND'd. Se qualquer regra falhar, o e-mail é rejeitado com rejection_reason=filters.
Regras de anexos permitidos
attachments_allow_rules decide quais anexos de um e-mail são processados. Cada regra pode ter:
| Chave | Tipo | Significado |
|---|---|---|
extensions | string[] | Extensões sem o ponto, sem diferenciar maiúsculas: ["pdf", "xml"]. |
filename_pattern | string | Expressão regular JavaScript testada contra o nome do arquivo, até 200 caracteres: ^GUIA_. Quantificadores aninhados são recusados. |
case_sensitive | bool | Vale para filename_pattern. Padrão false. |
Uma regra precisa de extensions, filename_pattern ou dos dois; dentro de uma regra, todas as chaves informadas precisam ser atendidas. Um anexo é processado quando atende a qualquer regra. Até 20 regras.
[{ "extensions": ["pdf"], "filename_pattern": "^GUIA_" }]
processa só os PDFs cujo nome começa com GUIA_ (sem diferenciar maiúsculas).
Um anexo fora da lista é ignorado, nunca um motivo para rejeitar o e-mail:
- o agente não o vê — os outros anexos mantêm o número (
Anexo 1,Anexo 3); - os
attachments_max_*contam só os anexos que passaram; - um passo de workflow que o referencia (
${{email.attachments.N}}) falha antes de qualquer requisição; - o e-mail registra o anexo em
metadata.ignoredAttachments, como{ "index": N, "reason": "not_allowed" }(a partir de 0, oNde${{email.attachments.N}}). Um reprocessamento refaz a lista com as regras atuais; quando rejeita o e-mail, a chave é removida.
Um anexo sem nome (o logo inline de uma assinatura, por exemplo) nunca atende a uma regra. Quando nenhum anexo passa, o agente roda mesmo assim sobre o corpo. null ou [] processa todos os anexos.
Exemplo
{
"id": "b3c4d5e6-7a89-4b0c-9d1e-2f3a4b5c6d7e",
"external_id": "00000000-0000-0000-0000-00000000001a",
"workspace_id": "a8b2c1d4-9e7f-4a3b-8c5d-1f2e3a4b5c6d",
"agent_id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
"label": "Suporte — Triagem",
"email": "triage-3f4a@inbox.kobana.com.br",
"status": "active",
"allowed_recipients": ["support@acme.com"],
"filters": [{ "field": "from", "op": "matches", "value": ".*@(acme|partner)\\.com$" }],
"attachments_allow": true,
"attachments_max_file_number": 10,
"attachments_max_file_size": 10485760,
"attachments_max_total_size": 41943040,
"attachments_allow_rules": null,
"custom_metadata": { "team": "support" },
"metadata": {},
"created_at": "2026-01-04T12:00:00.000Z",
"updated_at": "2026-01-04T12:00:00.000Z",
"deleted_at": null
}
Ciclo de vida
POST /inboxes— cria (sem efeitos na AWS).PATCH /inboxes/{id}— atualiza label, filtros, destinatários permitidos, política de anexos, agente associado.DELETE /inboxes/{id}— soft-delete. E-mails futuros para o endereço são rejeitados comrecipient_unknown.
Setar status: "inactive" mantém a linha mas rejeita novos e-mails com recipient_unknown — útil para suspensões temporárias onde você pretende reativar.