Skip to main content

Inbox

Email for agents. Inbound and outbound flow through Firestore collections and the Inbox Cloud Functions.

Tables

TablePurpose
postbox.domainsVerified sending domains (SPF/DKIM/DMARC state).
postbox.addressesagent_id → address mapping with aliasing.
postbox.messagesEvery inbound and outbound row.
postbox.inbound_rulesPer-agent move/forward/auto-reply rules.
postbox.outbound_suppressionsHard-bounce block list.
postbox.send_quotasPer-agent per-window rate limits.
postbox.inbound_webhooksSigned callback endpoints.

Inbound flow

  1. MTA POSTs parsed MIME to postboxIngest with the bridge key.
  2. postboxIngest resolves to → agentId, scores for prompt injection, inserts, and applies matching rules.
  3. Raw MIME is uploaded to the postbox-mime bucket; the row is stamped via stamp_body_ref().
  4. Registered webhooks fire through Cloud Functions fetch with an HMAC signature and an x-ujex-webhook-timestamp header.

Outbound flow

  1. Agent calls postboxSend with a stable sessionId. The callable checks auth, quotas, suppressions, approval policy, and writes an outbound row.
  2. The bridge dispatch path ships queued rows and records delivery or bounce.
  3. is_hard_bounce(reason) auto-suppresses addresses on terminal codes.

Prompt injection scoring

postbox.detect_prompt_injection(body) returns a 0–1 float. Every inbound row carries injection_score and quarantined = (score > 0.8). Agents that auto-act on mail should gate behavior on the score.

Routes

MethodPathPurpose
CallablePurpose
------
postboxIngestIngest parsed MIME (bridge key).
postboxSendSend outbound mail with required sessionId.
postboxListMessagesList messages for the authenticated agent.
postboxReadMessageRead one message.
postboxListInboxesList provisioned inboxes.
postboxBounceRecord bounce events.

Bounce handling

Postmark (or any bounce-emitting provider) POSTs to the postboxBounce webhook with an HMAC-SHA256 signature of the raw body using the shared POSTBOX_BOUNCE_SECRET. The handler:

  1. Verifies the signature in constant time and rejects mismatches with 401 — never an explanation that would aid forgery.
  2. Looks up the outbound row by messageId (or MessageID) and writes a bouncedAt / bounceType / bounceDetail triple.
  3. Updates the recipient's reputation in owners/{uid}/emailReputation/{address}. HardBounce and SpamComplaint block future sends to that address for 30 days.
  4. Appends a postbox.bounce audit row.

This is the single source of truth for "don't email this person again." Deliverability dashboards read from emailReputation; the sender-side send call checks it before debiting the quota.

Retention

ujex_postbox_retention (03:17 UTC daily) hard-deletes rows past postbox_retention_days (default 90). MIME blobs are reaped alongside.