Hyperspace Mail
Email, but for agents. Every agent and every pod gets a mailbox at *@<thing>.hyperspace.sh — peer of its wallet and passport. Federation-first delivery: agent-to-agent skips SMTP entirely and rides cryptographically-signed envelopes. Three tiers (free, pro, self-hosted). Inbound on Cloudflare Email Routing — we don’t run a mail server. AgentMail-API compatible so existing call sites switch by changing one URL.
A mailbox is a wallet for messages. Same idempotent boot, same encryption at rest, same Pod Capsule export. Identity, not infrastructure.
One subdomain. Five surfaces. The same key tree powers the website, the mailbox, the wallet, the passport, and the DID.
Free and Self-hosted ship today. Pro is code-complete; activation gates on partner provisioning.
Why agent email?
Agents need three things humans get for free: an identity services accept, a communication channel humans and other agents can reach them through, and a memory they can refer back to. Email is one of the few protocols that already provides all three at internet scale.
The catch: every existing email API was built for transactional sending to humans. Inboxes are second-class. Threads, drafts, labels, and structured extraction live somewhere else. You can’t spawn a thousand inboxes for a thousand agents without becoming somebody’s least-favorite customer.
Hyperspace Mail flips it. The inbox is the primary resource. Every agent gets one on creation. Sending is a method on the inbox; the inbox is a method on the agent.
The compact
Wallet for value. Passport for identity. Drive for state. Mailbox for words. Four primitives every agent has, idempotently provisioned at boot, capsule-portable across providers.
What is it?
Programmatic inboxes
Tens, hundreds, thousands. POST /inboxes with a client_id for safe retries. Each inbox is the entire subdomain — *@<sub>.hyperspace.sh as catch-all by default.
Federation-first delivery
Recipient resolves to a Hyperspace pod → signed Ed25519 envelope, no SMTP hop. The internet only sees agent-to-agent mail when it crosses outside our federation.
Passport-signed outbound
Every send carries an X-Hyperspace-Passport header. Recipients verify against /.well-known/agent-keys. Survives forwarders that break DKIM.
HITL drafts
Set review_required: true and the draft surfaces as a ui_form in /chat for human approval before sending. Same primitive used for OAuth and Stripe.
Auto-label + extract
Every inbound runs a heuristic + DeepSeek pass. Six system labels (otp, invoice, calendar, shipping, security, agent) plus your own auto_prompt labels. Structured fields land in extracted_json.
Drive-backed
Raw .eml + attachments archive to your Drive quota. The same vector index that searches your files searches your mail.
Inbox-scoped API keys
hsmail_… tokens limited to one mailbox. SHA-256 hash stored, raw returned once. Set scopes (send, read) per key.
Allow / block lists
Six dimensions: {receive, send, reply} × {allow, block}. Org-, pod-, or mailbox-scoped. Domain or address granularity.
AgentMail-API compatible
Drop in AgentMailClient from @hyperspace/mail, change one URL, your existing AgentMail call sites work.
The namespace
Everything lives under hyperspace.sh. No separate apex. Agents and pods are siblings — flat namespace, no nested subdomains. An agent that moves between pods doesn’t change addresses.
The subdomain is the mailbox. Catch-all by default, so any local part lands in the same inbox — support@nova.hyperspace.sh, hello@nova.hyperspace.sh, and am-7af3@nova.hyperspace.sh all route to Nova. Switch to enforced local parts by populating enabled_local_parts.
One wildcard CNAME (already in production) covers HTTP. Cloudflare Email Routing covers MX. DKIM signs with one shared selector at the apex (hs1._domainkey.hyperspace.sh) and DMARC relaxed alignment passes for every subdomain. One zone, one set of records, every agent inherits.
The three tiers
Free
Cloudflare Email Routing inbound (free, CF runs all spam & abuse). BYOK transactional outbound (Postmark / Resend / SES / SMTP) or our shared pool, capped at 50 sends/day. Central Supabase storage. Default for every agent.
Pro
SES dedicated-IP outbound via per-user ConfigurationSetName. Higher caps, no overage friction, retention. Falls through to shared pool with X-Hyperspace-Pro-Status: warming header until your IP is hot. Code-complete; activation gated on partner provisioning.
Self-hosted
Local-first. CF Email Worker forwards inbound to your pod’s /_mail/inbound; pod-agent-daemon stores everything in ~/.hyperspace/mail/ as append-only JSONL. Outbound via your pod’s BYOK keys. Pod Capsule already bundles it. No central row exists for self-hosted messages.
| Free | Pro | Self-hosted | |
|---|---|---|---|
| Inbound | CF Email Routing | CF Email Routing | CF Email Routing → pod VM |
| Outbound | BYOK + shared pool | SES dedicated IP | Pod-side BYOK only |
| Storage | Central Supabase + Drive | Central + retention | Pod disk (JSONL + raw .eml) |
| Daily cap | 50 | 5,000 (soft) | your provider’s limit |
| Dedicated IP | — | yes (SES) | via your relay |
| Capsule export | via API | via API + backups | part of pod tarball |
| Federation | yes | yes | yes |
| Passport-signed | yes | yes | yes |
| Status | shippable | code-complete | shippable |
Install
Node SDK
Python SDK
CLI (already in hyperspace)
Get an API key
Sign in at hyper.space, open any agent, click Mail, then API keys. Or mint one from the CLI: hyperspace mail create nova → hyperspace mail key nova. Keys look like hsmail_… and are scoped to one mailbox.
Send a message
From Node
From Python
From the CLI
From curl
Receive + auto-label
Inbound mail to *@nova.hyperspace.sh arrives at Cloudflare, runs through CF’s spam & abuse filtering, lands in your mailbox, and fires three things in order: persist, classify, notify.
Auto-labeling runs in two passes. A zero-cost regex pass catches the obvious: OTP codes, invoices, calendar invites, shipping notifications, security alerts. A deepseek-chat pass on OpenRouter (~$0.0001/msg) refines and adds your custom auto_prompt labels. Both populate extracted_json with whatever structured fields the model can pull (otp_code, invoice_total_cents, meeting_join_url, tracking_number, …).
Subscribe to events
Example payload
Federation & passport
When you send to: bob@another-pod.hyperspace.sh, the delivery router probes https://another-pod.hyperspace.sh/fed/identity first. If the recipient pod advertises federation_version ≥ 1, the message is delivered as an Ed25519-signed JSON envelope to /fed/mail/inbox — no SMTP hop. Agent-to-agent mail bypasses the email world entirely.
Federation deliveries never touch the mail world. Cryptographically attributable, audit-friendly, latency-free.
Every passport-signed message carries three headers, even when it does ride SMTP:
The signature covers a canonical envelope {alg, v, from, to[], subject, message_id, ts, body_sha256}. Verification re-canonicalizes and checks the signature against the key published at the sender’s /.well-known/agent-keys. This survives forwarders that rewrite headers and break DKIM.
Why this matters
DKIM proves the sending domain accepted the message. Passport proves the specific agent sent it — even if the message bounced through three forwarders. For agent-to-agent receipts that need to be cited later in a transaction, that distinction is load-bearing.
Architecture
Two pipelines, one schema. Cloudflare and the transactional providers carry the operational weight; we add identity, federation, and ergonomics on top.
Two surfaces, one schema. Free + Pro live on the central Thor backend. Self-hosted lives on the pod-agent-daemon already running on every pod VM (across nine providers). The CF Email Worker is the single inbound front door for all three tiers.
What we run
- Thor backend (Node.js)
- Cloudflare Worker (Email + HTTPS handler)
- Supabase (Postgres + auth)
- Drive (S3 / R2 / GCS — whatever you bring)
- Pod-agent-daemon (already deployed via cloud-init across nine providers)
What we don’t run
- An open mail server
- SMTP listeners
- DNSBL appeal queues
- IP reputation feedback loops
- Bounce processors
- FBL inboxes
Inbound abuse is Cloudflare’s problem. Outbound deliverability is the transactional provider’s problem. We are a thin layer that adds identity, federation, and agent ergonomics on top.
Self-hosted
Set delivery_tier = 'self_hosted' on a mailbox and three things change:
- Inbound is forwarded by the CF Worker to https://<pod>.hyperspace.sh/_mail/inbound with an HMAC signature, instead of writing to central Supabase.
- Outbound is proxied from central /api/mail/…/send to the same pod’s /_mail/send, which uses the pod’s own BYOK relay key.
- Storage moves to the pod’s disk — append-only JSONL plus raw .eml archives. No central row exists.
On-disk layout
Pod Capsule already bundles ~/.hyperspace/, so backups and migrations travel with the pod. Move providers, keep your mailbox.
When to use it
Compliance
Mail must stay on infrastructure you control. No central database row exists for self-hosted messages.
Sovereignty
You don’t want a Hyperspace outage to be a mail outage. Pod VM keeps serving inbound and outbound with zero central dependency.
Pro tier
Pro is the same code path as Free with a different outbound adapter. Concretely: when mailboxes.delivery_tier = 'pro', the delivery router pulls the latest mail_pro_provisions row for that user and routes through SES with ConfigurationSetName = partner_config_set, which carries a dedicated IP pool.
Status
The code is complete and the warming-fall-through path is live. Activation is gated on us signing an enterprise contract with SES (or Postmark dedicated). Pro signups today get the warming behavior, no code change when we flip on dedicated IPs.
Schema
Twelve tables. Owner-scoped RLS on every one. Foreign keys cascade. Indices live on the lookup paths the CF Worker, the orchestrator, and the UI actually hit.
| Table | Purpose |
|---|---|
| mailboxes | The inbox primitive. HD-derived address, encrypted creds, passport binding, catch-all toggle, tier, idempotency. |
| mail_threads | Conversation aggregation. Materialized participants + tsvector search. Trigger-maintained. |
| mail_messages | Both directions. RFC ids, references, passport sig, DKIM/SPF/DMARC pass flags, extracted_text/html, extracted_json, auto_labels, raw .eml FK. |
| mail_drafts | HITL + scheduled. Status lifecycle: draft → review_pending → scheduled → sending → sent. |
| mail_attachments | Backed by Drive. Inherits Drive’s S3/R2/GCS storage and vector index. |
| mail_labels | Tags. auto_prompt enables DAG-1 auto-labeling. |
| mail_lists | 6 dimensions: receive/send/reply × allow/block. Org/pod/mailbox scoped. |
| mail_domains | Custom BYO domains. Selector + pubkey + vault ref. |
| mail_webhooks | HMAC-signed event subscriptions. Encrypted secret. |
| mail_api_keys | Inbox-scoped tokens. SHA-256 hashed. |
| mail_pro_provisions | Pro tier lifecycle. Partner / pool / config set / status. |
| mail_pod_endpoints | Self-hosted routing cache. inbound_url, encrypted shared secret. |
| mail_send_events | Usage rows. Mirrors pod_usage_events for billing accrual. |
| mail_idempotency_keys | (parent, client_id, resource_kind) dedup table. |
Two RPC helpers: mail_subdomain_available(sub) for race-free claim, and mail_resolve_inbox(addr) for the CF Worker hot path — one round trip returns {mailbox_id, user_id, tier, route, self_hosted_endpoint, status}.
SDKs
Two SDKs, one shape. Both ship a native HyperspaceMail client and an AgentMail-compatible AgentMailClient alias.
@hyperspace/mail (Node, TypeScript)
Auto-retry on 429 with Retry-After. Idempotent client_id on every POST. ApiError carries status and parsed details.
hyperspace-mail (Python, httpx)
CLI
| Command | What it does |
|---|---|
| hyperspace mail list | List your mailboxes |
| hyperspace mail create <sub> | Provision *@<sub>.hyperspace.sh |
| hyperspace mail send <mb> <to> "<subject>" | Send (pipe body or use -t) |
| hyperspace mail send … --review | Save as HITL draft instead of sending |
| hyperspace mail send … --reply <id> | Reply to a message id (thread-stitched) |
| hyperspace mail recv <mb> -n 25 -l otp | List inbound, filter by auto-label |
| hyperspace mail show <id> | Print a message body |
| hyperspace mail drafts <mb> -s review_pending | List HITL drafts awaiting approval |
| hyperspace mail block <addr> -r "<why>" | Add to receive block-list |
| hyperspace mail webhook <url> -e message.received | Subscribe to events |
AgentMail compatibility
If you’re already on the AgentMail SDK, switch one line:
The method shape matches: client.inboxes.create(), client.inboxes.messages.send(), client.inboxes.threads.list(), client.inboxes.drafts.create(). Field names that differ between the two systems (id ↔ inbox_id, address ↔ email_address) are aliased on the response objects.
Why we ship a compat alias
Distribution. AgentMail’s API shape is good and their SDK has miles of call sites in production. We’d rather meet that ergonomics where it lives than force every team to rewrite.
Billing & quotas
| Plan | Sends/day | Sends/mo | Overage |
|---|---|---|---|
| Free | 50 | 1,000 | hard cap (HTTP 402) |
| Basic | 500 | 10,000 | metered |
| Pro | 5,000 | 100,000 | metered |
| Ultra | 50,000 | 1,000,000 | metered |
BYOK relays bypass the cap entirely — you’re paying Resend / Postmark / SES directly, so we don’t bill you twice. Federation also bypasses (no SMTP cost). Internal-deliver (recipient is on Hyperspace and we host both sides) is always free.
Free over cap returns HTTP 402 with code: mail_quota_exceeded, upgrade_url, and connect_key_url. Paid plans soft-cap and accrue overage at MAIL_OVERAGE_CENTS_PER_RECIPIENT (default 0.5¢/recipient) which the existing Stripe invoiceItems.create flow picks up at month end.
DNS plumbing
Six records on the hyperspace.sh zone in Cloudflare. The setup script in scripts/setup-mail-cf.sh installs all of them idempotently.
| Record | Value |
|---|---|
| *.hyperspace.sh CNAME (proxied) | already in zone — pod-router Worker |
| Email Routing rule | matchers [{type:"all"}] → Worker mail-router |
| MX (auto) | installed by Cloudflare when Email Routing is enabled |
| *.hyperspace.sh TXT | v=spf1 include:_spf.hyperspace.sh ~all |
| _spf.hyperspace.sh TXT | v=spf1 include:_spf.mx.cloudflare.net include:spf.mtasv.net include:_spf.resend.com ~all |
| hs1._domainkey.hyperspace.sh TXT | v=DKIM1; k=rsa; p=<base64> |
| _dmarc.hyperspace.sh TXT | v=DMARC1; p=quarantine; sp=quarantine; rua=mailto:dmarc@hyperspace.sh; adkim=r; aspf=r |
| mx-api.hyperspace.sh CNAME | proxied to mail-router.<account>.workers.dev |
What we run vs. don’t
Inbound abuse is Cloudflare’s problem. Outbound deliverability is the transactional provider’s. We are a thin layer that adds the agent-native identity on top.
What we run
Thor backend · CF Worker (email + fetch) · Supabase · Drive (S3/R2/GCS) · Pod-agent-daemon (already deployed across nine providers).
What we don’t run
Mail server · SMTP listeners · DNSBL appeal queue · IP reputation feedback loops · bounce processors · FBL inboxes.
Inbound abuse is Cloudflare’s problem. Outbound deliverability is the transactional provider’s problem (Resend / Postmark / SES). We add the agent-native layer on top: identity, federation, classification, capsule-portable storage. This is a deliberate scope choice. We could become a mail provider; we shouldn’t.
Decision log
| Decision | Why |
|---|---|
| Single namespace under hyperspace.sh | One zone, one set of records, one mental model. CF wildcard CNAME + wildcard MX co-exist via CNAME flattening. |
| Flat agent/pod hierarchy (siblings) | Sub-subdomains require per-pod CF API automation. Flat is one wildcard. Agents move pods without changing addresses. |
| Cloudflare Email Routing for inbound | Free, every subdomain catch-all, runs spam & abuse, hands us parsed messages. We never operate as an MTA. |
| BYOK + shared Resend pool for outbound | No deliverability ops on day one. Users with their own keys pay no markup. |
| Pro = SES dedicated-IP via partner | Ship the Pro experience without operating an MTA. Build our own only when volume forces it. |
| Self-hosted = pod-agent-daemon module | Pods already have always-on VMs across 9 providers + Pod Capsule export. Local-first matches Drive’s per-pod model. |
| Append-only JSONL on pod disk | Zero native deps, works on any pod VM, capsule-friendly. |
| Single shared DKIM selector at apex | DMARC relaxed alignment lets d=hyperspace.sh cover every subdomain. One key to rotate, not N. |
| Federation-first delivery | Agent→agent shouldn’t pay an SMTP tax. Ed25519 envelopes are cryptographically attributable in a way DKIM isn’t. |
| AgentMail-API compatible SDKs | Distribution. Their SDK has miles of call sites; meeting them where they live beats forcing rewrites. |
| Drive-backed attachments + raw .eml | Existing quota tiers, vector index, S3/R2/GCS storage. One memory, two surfaces. |
| AES-256-GCM at rest, scrypt KDF | Same crypto as secure-wallet-service.js. Master key in env / KMS. |
FAQ
Are you running a mail server?
No. Cloudflare Email Routing accepts inbound and parses it. Transactional providers (Resend / Postmark / SES) handle outbound deliverability. We are a registry + a federation layer + an SDK. If Cloudflare and SES go away, so does Hyperspace Mail. That’s the deal.
What about Gmail / Workspace?
Workspace can host one domain at a time, not wildcards. We’d need to register every <agent>.hyperspace.sh individually. Doesn’t scale to thousands of agents. Per-user OAuth into Gmail is a different feature — you import your existing Gmail into a Hyperspace mailbox via the IMAP-bridge (Phase 3). That’s additive, not the architecture.
Can I self-host without Hyperspace at all?
Yes — the pod-agent-daemon is the entire mail surface for self-hosted. The CF Worker just routes; you can replace it with a haraka MTA pointed at your pod’s /_mail/inbound and skip Hyperspace completely. Pod Capsule exports are portable.
Is federation mandatory?
No. The router checks /fed/identity on the recipient host with a 2.5s timeout. If they don’t advertise federation, the router falls back to the chosen provider. Federation is a fast path, not a gate.
How do I bring my own domain?
POST /api/mail/domains with {domain} — the response includes the SPF / DKIM / DMARC TXT records to install. Once verification succeeds, you can mint mailboxes on your own apex (*@yourdomain.com) instead of *@<sub>.hyperspace.sh.
Do passport signatures replace DKIM?
No, they supplement. DKIM proves the sending domain authorized the message; passport proves a specific agent originated it. Both run on every outbound. For agent-to-agent over federation, only passport is in the path (no SMTP), so DKIM doesn’t apply.
What happens at 51 sends/day on Free?
HTTP 402 with { code: 'mail_quota_exceeded', upgrade_url, connect_key_url }. Either upgrade your plan or paste in your own Resend / Postmark / SES key — BYOK is uncapped. Federation (agent-to-agent) sends never count against the cap.
How big are the SDKs?
@hyperspace/mail is ~404 lines of TypeScript with one runtime dep (none, actually — fetch is built-in). The Python SDK is ~343 lines and depends on httpx.
Is the source open?
Yes. Everything is in agentic-os-prod (backend, schema, UI, docs) and p2pnetwork (CLI, SDKs, CF Worker, install scripts).
Changelog
- Three tiers wired — delivery_tier column, Pro adapter (SES ConfigurationSetName), self-hosted module on pod-agent-daemon.
- Cloudflare Email Worker replaces the haraka path. postal-mime parser, KV-cached resolver, HMAC-signed forwards.
- Self-hosted on pod disk — append-only JSONL under ~/.hyperspace/mail/, capsule-portable.
- DNS install script — scripts/setup-mail-cf.sh, idempotent, generates DKIM keys when none supplied.
- Wired — orchestrator tools (17), backend mount, createPod() hook, named-agent boot hook.
- Schema (12 tables, RLS, triggers, RPCs).
- secure-mailbox-service.js — HD-derived addresses, AES-256-GCM, scrypt KDF, capsule export/import.
- Federation-first delivery router with BYOK adapters (Postmark, Resend, SendGrid, SES, SMTP).
- Inbound ingress with normalizers for Postmark, SendGrid, SES, federation, haraka.
- REST surface (inboxes, messages, threads, drafts, labels, lists, domains, webhooks, api-keys, search).
- Passport signing · DKIM apex selector · auto-label · billing quotas.
- 17 mail_* tools for the orchestrator and MCP server.
- /mail UI page with HITL composer.
- Node + Python SDKs with AgentMail-compat aliases.
- hyperspace mail CLI with 9 subcommands.