Skip to main content

Inbox

An Inbox is a routable email address with a processing policy. Each inbox belongs to one workspace and may bind a single agent for automated processing.

Purpose​

  • Provide a unique email address for a use-case (support triage, invoice intake, contract review, etc.).
  • Define filters that decide whether an inbound email is approved or rejected.
  • Control attachment policy (count, per-file size, total size).
  • Optionally route every approved email to an Agent for LLM processing.

Important: provisioning is database-only​

Creating an inbox does not call AWS. AWS SES inbound matches by domain — with the Domain Identity verified and MX records pointed, every address *@inbox.{env}.kobana.com.br reaches SES regardless of whether it exists in our database. The inbox row is what makes the address routable downstream; without it the email is dropped at process-email with rejection_reason=recipient_unknown.

Schema​

FieldTypeDescription
idUUIDInternal id.
external_idUUIDStable id from the source system. Unique.
workspace_idUUIDOwning workspace.
agent_idUUID | nullOptional agent for approved emails.
labelstringHuman label.
emailstringThe routable address. Globally unique.
statusenumactive or inactive.
allowed_recipientsstring[]When non-empty, only emails whose to includes one of these addresses are approved. Wildcards (*@acme.com) supported.
filtersJSONArray of filter rules (see below).
attachments_allowboolWhether attachments are allowed at all.
attachments_max_file_numberintMax attachments per email. Default 10.
attachments_max_file_sizeintBytes. Default 10485760 (10 MiB).
attachments_max_total_sizeintBytes. Default 41943040 (40 MiB).
attachments_allow_rulesarray|nullAllow list of attachments. null processes every attachment. See Attachment allow rules.
custom_metadataobjectFree-form.
metadataobjectSystem-controlled.
created_at / updated_at / deleted_atdatetime

Filters​

The filters field is a JSON array. Each element is a rule like:

{ "field": "from", "op": "matches", "value": "^.*@acme\\.com$" }
fieldopvalue
from, subject, header.<name>equals, contains, matches (regex)string
headers.list-idpresent, absent(no value)
body.textcontainsstring

Rules are AND'd. If any rule fails the email is rejected with rejection_reason=filters.

Attachment allow rules​

attachments_allow_rules decides which attachments of an e-mail are processed. Each rule may carry:

KeyTypeMeaning
extensionsstring[]Extensions without the dot, case-insensitive: ["pdf", "xml"].
filename_patternstringJavaScript regular expression tested against the filename, up to 200 characters: ^GUIA_. Nested quantifiers are refused.
case_sensitiveboolApplies to filename_pattern. Default false.

A rule needs extensions, filename_pattern or both; inside a rule every key given must match. An attachment is processed when it matches any rule. Up to 20 rules.

[{ "extensions": ["pdf"], "filename_pattern": "^GUIA_" }]

processes only the PDFs whose name starts with GUIA_ (any case).

An attachment outside the list is ignored, never a reason to reject the e-mail:

  • the agent does not see it — the other attachments keep their number (Anexo 1, Anexo 3);
  • attachments_max_* count only the attachments that passed;
  • a workflow step that references it (${{email.attachments.N}}) fails before any request is sent;
  • the e-mail records it in metadata.ignoredAttachments, as { "index": N, "reason": "not_allowed" } (0-based, the N of ${{email.attachments.N}}). A reprocess decides the list again under the current rules; when it rejects the e-mail, the key is removed.

An attachment without a filename (an inline signature logo, say) never matches a rule. When no attachment passes, the agent still runs on the body. null or [] processes every attachment.

Example​

{
"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": "Support — Triage",
"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
}

Lifecycle​

  • POST /inboxes — create (no AWS side effects).
  • PATCH /inboxes/{id} — update label, filters, allowed recipients, attachment policy, bound agent.
  • DELETE /inboxes/{id} — soft-delete. Future emails to the address are rejected with recipient_unknown.

Setting status: "inactive" keeps the row but rejects new emails with recipient_unknown — useful for temporary suspensions where you plan to reactivate.