hyperspace
Documentation · v0.2 · free + self-hosted shippable

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.

Install Read the spec
# 60-second start — give your agent its first email npx hyperspace mail create nova # → *@nova.hyperspace.sh curl -X POST https://api.hyperspace.sh/api/mail/inboxes/$ID/messages/send \ -H "authorization: Bearer $HSMAIL_KEY" \ -H "content-type: application/json" \ -d '{"to":"founder@example.com","subject":"hi","text":"first send from your agent"}'
A mailbox is a wallet for messages — same HD derivation, same AES-256-GCM, same capsule export

A mailbox is a wallet for messages. Same idempotent boot, same encryption at rest, same Pod Capsule export. Identity, not infrastructure.

<thing>.hyperspace.sh is one identity with five surfaces: web, mail, wallet, passport, DID

One subdomain. Five surfaces. The same key tree powers the website, the mailbox, the wallet, the passport, and the DID.

Three tiers — Free / Pro / Self-hosted — same primitives, different infrastructure

Free and Self-hosted ship today. Pro is code-complete; activation gates on partner provisioning.

3tiers — free, pro, self-hosted
0SMTP hops for agent-to-agent (federation)
17mail_* tools wired into the orchestrator
2SDKs — Node + Python — AgentMail-compatible
~11.6kLOC across 22 files
0mail servers we operate
Why agent email? What is it? The namespace The three tiers Install Send a message Receive + auto-label Federation & passport Architecture Self-hosted Pro tier Schema SDKs CLI AgentMail compatibility Billing & quotas DNS What we run Decision log FAQ Changelog

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.

nova.hyperspace.sh ← agent Nova: *@nova.hyperspace.sh, https://nova.hyperspace.sh acme.hyperspace.sh ← pod Acme: *@acme.hyperspace.sh, https://acme.hyperspace.sh hyperspace.sh ← apex / dashboard

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

F

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.

P

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.

S

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.

 FreeProSelf-hosted
InboundCF Email RoutingCF Email RoutingCF Email Routing → pod VM
OutboundBYOK + shared poolSES dedicated IPPod-side BYOK only
StorageCentral Supabase + DriveCentral + retentionPod disk (JSONL + raw .eml)
Daily cap505,000 (soft)your provider’s limit
Dedicated IPyes (SES)via your relay
Capsule exportvia APIvia API + backupspart of pod tarball
Federationyesyesyes
Passport-signedyesyesyes
Statusshippablecode-completeshippable

Install

Node SDK

npm i @hyperspace/mail # or pnpm add @hyperspace/mail bun add @hyperspace/mail

Python SDK

pip install hyperspace-mail # or uv add hyperspace-mail

CLI (already in hyperspace)

curl -fsSL https://hyper.space/install | bash hyperspace mail list

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 novahyperspace mail key nova. Keys look like hsmail_… and are scoped to one mailbox.

Send a message

From Node

import { HyperspaceMail } from '@hyperspace/mail'; const client = new HyperspaceMail({ apiKey: process.env.HSMAIL_KEY }); const inbox = await client.inboxes.create({ username: 'nova', client_id: 'first-run', // idempotent retry-safe }); await client.inboxes.messages.send(inbox.id, { to: 'founder@example.com', subject: 'launch readout', text: 'agent finished. signing off — Nova.', });

From Python

from hyperspace_mail import HyperspaceMail with HyperspaceMail(api_key=os.environ["HSMAIL_KEY"]) as client: inbox = client.inboxes.create(username="nova", client_id="first-run") client.inboxes.messages.send( inbox.id, to="founder@example.com", subject="launch readout", text="agent finished. signing off — Nova.", )

From the CLI

hyperspace mail create nova hyperspace mail send nova founder@example.com "launch readout" -t "agent finished" # draft for human review (HITL) hyperspace mail send nova founder@example.com "big claim" -t "…" --review

From curl

curl -X POST https://api.hyperspace.sh/api/mail/inboxes "$INBOX_ID"/messages/send \ -H "authorization: Bearer $HSMAIL_KEY" \ -H "content-type: application/json" \ -d '{ "to": ["founder@example.com"], "subject": "launch readout", "text": "agent finished. signing off — Nova.", "client_id": "send-2026-04-29-001" }'

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.

1CF Emailspam, abuse, MX
2CF Workerparse, dedup
3resolvetier & route
4persistcentral or pod
5labelheuristic + LLM
6notifywebhook + Rail

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

await client.webhooks.create({ url: 'https://my.app/agent-mail-events', events: ['message.received', 'message.sent', 'mail.labeled'], secret: 'hmac-secret-here', }); // Each delivery includes: // X-Hyperspace-Event: message.received // X-Hyperspace-Signature: sha256=<hmac of body>

Example payload

{ "event": "message.received", "timestamp": "2026-04-29T18:42:01Z", "data": { "id": "7f1a-…", "mailbox_id": "…nova…", "from_addr": "github@notifications.github.com", "subject": "[hyperspaceai/p2pnetwork] PR #1234 ready", "extracted_text": "PR #1234 has all checks passing …", "auto_labels": ["agent", "github-pr"], "extracted_json": { "pr_number": "1234", "repo": "hyperspaceai/p2pnetwork" }, "passport_verified": false, "delivery_kind": "cloudflare" } }

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-first delivery: agent-to-agent skips SMTP, DKIM, MX, DNSBL — direct Ed25519-signed envelope

Federation deliveries never touch the mail world. Cryptographically attributable, audit-friendly, latency-free.

your agent (Nova) recipient pod (Acme) | | | POST /fed/mail/inbox | | X-Hyperspace-Passport: <sig> | | X-Hyperspace-Passport-Kid: … | |      {from, to, subject, message_id, ts, body_sha256} | -------------------------------->| | | verify ed25519 against | | /.well-known/agent-keys | | | 200 OK | |<---------------------------------| No DKIM, no SPF, no MX. Cryptographically attributable.

Every passport-signed message carries three headers, even when it does ride SMTP:

X-Hyperspace-Passport: base64url(ed25519 signature) X-Hyperspace-Passport-Kid: <pod_id>:<key_fingerprint> X-Hyperspace-Passport-Alg: ed25519

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

Inbound and outbound pipelines — Cloudflare runs spam, providers run deliverability, we run the registry

Two pipelines, one schema. Cloudflare and the transactional providers carry the operational weight; we add identity, federation, and ergonomics on top.

INBOUND OUTBOUND ——————— ———————— the sender’s MTA your agent | | v v [ Cloudflare Email Routing ] [ Hyperspace Mail SDK / API ] spam, abuse, MX, ACL sign with passport | | v v [ CF Email Worker ] [ Mail Delivery Router ] postal-mime parse 1. is recipient on Hyperspace? KV-cached resolver → federation envelope HMAC forward 2. else: pick adapter by tier | · free → BYOK / shared v · pro → SES dedicated IP resolve tier ? · self-h → pod-side BYOK +-- free → central | +-- pro → central (tier=pro) v +-- self-hosted → pod /_mail/inbound [ network ] | | v v [ store + label + notify ] [ recipient ]

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

What we don’t run

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:

  1. Inbound is forwarded by the CF Worker to https://<pod>.hyperspace.sh/_mail/inbound with an HMAC signature, instead of writing to central Supabase.
  2. Outbound is proxied from central /api/mail/…/send to the same pod’s /_mail/send, which uses the pod’s own BYOK relay key.
  3. Storage moves to the pod’s disk — append-only JSONL plus raw .eml archives. No central row exists.

On-disk layout

~/.hyperspace/mail/ <mailbox-id>/ messages.jsonl # append-only canonical rows threads.jsonl # last-write-wins on read drafts.jsonl raw/<rfc-message-id>.eml attachments/<sha256>-<name> send-events.jsonl # local accrual log

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.

[ user buys Pro plan ] | v mail_pro_provisions row inserted with status='requested' | | (operator workflow; no code change required) v status='warming' ← partner_config_set assigned, IP warming starts | | outbound transparently falls through to shared pool | with X-Hyperspace-Pro-Status: warming header v status='active' ← partner_pool_id, partner_ip, active_since populated | v hyperspacePro adapter ← SES configurationSetName = dedicated IP delivery

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.

TablePurpose
mailboxesThe inbox primitive. HD-derived address, encrypted creds, passport binding, catch-all toggle, tier, idempotency.
mail_threadsConversation aggregation. Materialized participants + tsvector search. Trigger-maintained.
mail_messagesBoth directions. RFC ids, references, passport sig, DKIM/SPF/DMARC pass flags, extracted_text/html, extracted_json, auto_labels, raw .eml FK.
mail_draftsHITL + scheduled. Status lifecycle: draft → review_pending → scheduled → sending → sent.
mail_attachmentsBacked by Drive. Inherits Drive’s S3/R2/GCS storage and vector index.
mail_labelsTags. auto_prompt enables DAG-1 auto-labeling.
mail_lists6 dimensions: receive/send/reply × allow/block. Org/pod/mailbox scoped.
mail_domainsCustom BYO domains. Selector + pubkey + vault ref.
mail_webhooksHMAC-signed event subscriptions. Encrypted secret.
mail_api_keysInbox-scoped tokens. SHA-256 hashed.
mail_pro_provisionsPro tier lifecycle. Partner / pool / config set / status.
mail_pod_endpointsSelf-hosted routing cache. inbound_url, encrypted shared secret.
mail_send_eventsUsage 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)

import { HyperspaceMail } from '@hyperspace/mail'; const client = new HyperspaceMail({ apiKey }); // Inboxes await client.inboxes.create({ username: 'nova', client_id: 'first-run' }); await client.inboxes.list({ pod_id }); await client.inboxes.get(id); await client.inboxes.update(id, { display_name: 'Nova' }); await client.inboxes.delete(id); // Messages await client.inboxes.messages.send(id, { to, subject, text }); await client.inboxes.messages.list(id, { limit, labels }); await client.inboxes.messages.get(id, mid); await client.inboxes.messages.reply(id, mid, { text, reply_all: true }); await client.inboxes.messages.forward(id, mid, { to }); await client.inboxes.messages.update(id, mid, { add_labels, remove_labels }); await client.inboxes.messages.raw(id, mid); // Threads, drafts, webhooks, lists, domains, api-keys await client.inboxes.threads.list(id); await client.inboxes.drafts.create(id, { to, subject, text, review_required: true }); await client.webhooks.create({ url, events, secret }); await client.lists.add('receive', 'block', { entry: 'spam.com' });

Auto-retry on 429 with Retry-After. Idempotent client_id on every POST. ApiError carries status and parsed details.

hyperspace-mail (Python, httpx)

from hyperspace_mail import HyperspaceMail with HyperspaceMail() as client: # reads HYPERSPACE_API_KEY env var inbox = client.inboxes.create(username="nova", client_id="first-run") msg = client.inboxes.messages.send( inbox.id, to="founder@example.com", subject="hi", text="first send", ) for m in client.inboxes.messages.list(inbox.id, limit=25)["messages"]: print(m.subject, m.auto_labels)

CLI

~/code/agent
$ hyperspace mail list Mailboxes *@nova.hyperspace.sh https://nova.hyperspace.sh agent=nova *@acme.hyperspace.sh https://acme.hyperspace.sh pod-bound $ hyperspace mail send nova founder@example.com "launch readout" -t "agent finished" ✓ Sent id=… status=delivered via=federation $ hyperspace mail recv nova -n 5 -l otp 2026-04-29 18:42 ← auth@stripe.com Sign-in code: 482911 [otp, security] id …
CommandWhat it does
hyperspace mail listList 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 … --reviewSave 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 otpList inbound, filter by auto-label
hyperspace mail show <id>Print a message body
hyperspace mail drafts <mb> -s review_pendingList HITL drafts awaiting approval
hyperspace mail block <addr> -r "<why>"Add to receive block-list
hyperspace mail webhook <url> -e message.receivedSubscribe to events

AgentMail compatibility

If you’re already on the AgentMail SDK, switch one line:

// Before import { AgentMail } from 'agentmail'; const client = new AgentMail({ apiKey }); // After import { AgentMailClient } from '@hyperspace/mail'; const client = new AgentMailClient({ apiKey: process.env.HSMAIL_KEY, baseUrl: 'https://api.hyperspace.sh', });

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 (idinbox_id, addressemail_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

PlanSends/daySends/moOverage
Free501,000hard cap (HTTP 402)
Basic50010,000metered
Pro5,000100,000metered
Ultra50,0001,000,000metered

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.

RecordValue
*.hyperspace.sh CNAME (proxied)already in zone — pod-router Worker
Email Routing rulematchers [{type:"all"}] → Worker mail-router
MX (auto)installed by Cloudflare when Email Routing is enabled
*.hyperspace.sh TXTv=spf1 include:_spf.hyperspace.sh ~all
_spf.hyperspace.sh TXTv=spf1 include:_spf.mx.cloudflare.net include:spf.mtasv.net include:_spf.resend.com ~all
hs1._domainkey.hyperspace.sh TXTv=DKIM1; k=rsa; p=<base64>
_dmarc.hyperspace.sh TXTv=DMARC1; p=quarantine; sp=quarantine; rua=mailto:dmarc@hyperspace.sh; adkim=r; aspf=r
mx-api.hyperspace.sh CNAMEproxied to mail-router.<account>.workers.dev
# Idempotent. Generates a fresh DKIM keypair if you don't supply one. CLOUDFLARE_API_TOKEN=… CLOUDFLARE_ZONE_ID=… \ ./scripts/setup-mail-cf.sh # Or preview without making changes: DRY_RUN=1 ./scripts/setup-mail-cf.sh

What we run vs. don’t

What we run vs what we don't — Hyperspace adds the agent layer; Cloudflare and providers carry the rest

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

DecisionWhy
Single namespace under hyperspace.shOne 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 inboundFree, every subdomain catch-all, runs spam & abuse, hands us parsed messages. We never operate as an MTA.
BYOK + shared Resend pool for outboundNo deliverability ops on day one. Users with their own keys pay no markup.
Pro = SES dedicated-IP via partnerShip the Pro experience without operating an MTA. Build our own only when volume forces it.
Self-hosted = pod-agent-daemon modulePods already have always-on VMs across 9 providers + Pod Capsule export. Local-first matches Drive’s per-pod model.
Append-only JSONL on pod diskZero native deps, works on any pod VM, capsule-friendly.
Single shared DKIM selector at apexDMARC relaxed alignment lets d=hyperspace.sh cover every subdomain. One key to rotate, not N.
Federation-first deliveryAgent→agent shouldn’t pay an SMTP tax. Ed25519 envelopes are cryptographically attributable in a way DKIM isn’t.
AgentMail-API compatible SDKsDistribution. Their SDK has miles of call sites; meeting them where they live beats forcing rewrites.
Drive-backed attachments + raw .emlExisting quota tiers, vector index, S3/R2/GCS storage. One memory, two surfaces.
AES-256-GCM at rest, scrypt KDFSame 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

v0.2.02026-04-29
v0.1.02026-04-29