Postbox
Email for agents. Inbound and outbound flow through postbox.* tables and
the agent-postbox Cloud Function.
Tables
| Table | Purpose |
|---|---|
postbox.domains | Verified sending domains (SPF/DKIM/DMARC state). |
postbox.addresses | agent_id → address mapping with aliasing. |
postbox.messages | Every inbound and outbound row. |
postbox.inbound_rules | Per-agent move/forward/auto-reply rules. |
postbox.outbound_suppressions | Hard-bounce block list. |
postbox.send_quotas | Per-agent per-window rate limits. |
postbox.inbound_webhooks | Signed callback endpoints. |
Inbound flow
- MTA POSTs parsed MIME to
/ingestwithx-agentpack-key. postbox.ingest()resolvesto → agent_id, scores for prompt injection, inserts, and applies matching rules.- Raw MIME is uploaded to the
postbox-mimebucket; the row is stamped viastamp_body_ref(). - Registered webhooks fire through
Cloud Functions fetchwith an HMAC signature and anx-agentpack-webhook-timestampheader.
Outbound flow
- Agent calls
/send.postbox.enqueue_outbound()checks quotas and suppressions, writes a row withdirection='out',status='queued'. - MTA polls
postbox.next_outbound_batch(), ships, and callsrecord_send_resultorrecord_bounce. 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
| Method | Path | Purpose |
|---|---|---|
| POST | /ingest | Ingest parsed MIME (bridge key). |
| POST | /alloc | Allocate an address for an agent. |
| POST | /send | Send outbound mail. |
| POST | /list | List messages (direction, limit, since). |
| POST | /mark_read | Mark ids read. |
| POST | /rule/put | Create/update an inbound rule. |
| POST | /webhook/register | Register a signed inbound webhook. |
| POST | /webhook/rotate | Dual-secret rotation. |
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:
- Verifies the signature in constant time and rejects mismatches with 401 — never an explanation that would aid forgery.
- Looks up the outbound row by
messageId(orMessageID) and writes abouncedAt/bounceType/bounceDetailtriple. - Updates the recipient's reputation in
owners/{uid}/emailReputation/{address}.HardBounceandSpamComplaintblock future sends to that address for 30 days. - Appends a
postbox.bounceaudit 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
agentpack_postbox_retention (03:17 UTC daily) hard-deletes rows past
postbox_retention_days (default 90). MIME blobs are reaped alongside.