A sovereign, AI-native email service on the Internet Computer. Enterprises install Open Email on their own IC cloud engine to run a self-hosted replacement for Gmail — where the data graph lives inside a canister and the primary interface is an AI that can see the schema, query it, and act on it.
Part of the Open series (alongside Open HR and Open Accounts). Open Email reuses the same fictional company — Helvetra — and the same Customer Success people as Open HR, so the three apps demo together as one coherent workspace.
Stage 1 is receive-first. There is no live SMTP/IMAP ingestion yet (no skill existed for it at build time), so the mailbox is driven by a deterministic preloaded corpus. The schema is shaped so real inbound ingestion can simply append
Messages later.
Traditional email apps make you click through folders. Open Email reimagines the UX around an assistant. You ask, in plain language, and the AI:
- Reads the live mail graph through OQL (
schema()+execute()) — a generic, discoverable query surface over the canister's state. - Acts on it through a small, permissioned, audited write API — mark threads read, move them to folders, flag escalations urgent, set status.
So a Customer Success lead can ask:
- "Which Customer Success rep has exchanged the most email with customers?" → volume ranking
- "Who appears to be having the most successful interactions?" → resolution rate + CSAT ranking
- "Flag every unanswered escalation as urgent." → the AI queries the matching thread ids, then calls
flagThreadsUrgent— they move into Needs urgent reply. - "Mark everything from Northwind Logistics as read."
The demo data is deliberately shaped so the busiest rep is not the happiest — the volume leader (Oscar Lee, 189 customer emails) trails the CSAT leader (Theo Bergström, 4.5/5) — giving the AI a real volume-vs-quality story to surface, not just a single ranking.
backend/ Motoko persistent actor (the live mail graph)
types.mo Mailbox · Contact · Account · Thread · Message · Company + access/AI/audit types
main.mo OQL Expose entities + edges + domains · AIware update API · LLM gateway · II auth + invites + audit · seed endpoints
vendor/oql/ the OQL Motoko library (schema()/execute()), from caffeinelabs/oql-prototype
src/
data/ types.ts (TS mirror) · generate.ts (shared Open HR people) · emailGraph.ts (deterministic mail corpus)
ic/ idl.ts (hand-written Candid) · backend.ts · auth.ts (Internet Identity) · convert.ts
lib/ai/ agent.ts (provider-neutral agent loop: Claude + Gemini, tools = query_data + the mailbox actions) · queryEngine.ts (offline fallback)
app/ AppContext (auth) · DataContext (canister-first mail state + actions)
components/, pages/ Inbox (reimagined three-pane) · AskAI · DataExplorer (OQL) · Settings · the AI slide-over
scripts/seed.ts loads the corpus into the canister
- One persistent actor holds the whole graph via enhanced orthogonal persistence (no
stable, no manual serialization). - OQL turns "one getter per question" into a single generic surface the AI drives dynamically. Forward edges join server-side via dotted paths (
message → contactId.kind,mailboxId.departmentId.name). OQL is gated to controllers + admins; per-user row scoping (a CSM seeing only their own mailbox) is on the roadmap and anchors on the grant↔mailbox link. - The LLM runs through the canister.
llmChatmakes a non-replicated HTTPS outcall to the chosen provider (Anthropic or Gemini); the API key is set by an admin and stored write-only — it never leaves canister memory. - The frontend is a certified asset canister. React + Vite + Tailwind.
See SPEC.md for the full data model and PRODUCTION.md for the mainnet-hardening checklist.
Prerequisites: icp (Node ≥ 22), mops, and Node deps.
npm install
# 1. Start a local replica (managed network, OS-assigned port — no collisions)
icp network start -d
# 2. Build + deploy the backend and frontend canisters
icp deploy
# 3. Load the demo mail corpus (19 mailboxes · 24 accounts · 50 contacts · 560 threads · 2,253 messages)
npm run seed
# 4. Run the dev server (http://localhost:3100)
npm run devOpen http://localhost:3100, choose "Continue as demo viewer" (an always-granted owner for local testing), and you land in the Inbox.
To enable the live AI (not just the offline query engine), open Settings → AI assistant and paste an Anthropic or Gemini API key. The key is stored write-only in the canister. Without a key, the Ask AI page still answers the built-in customer-success questions via the offline engine, and all the canister-backed actions (mark read, move, flag urgent) work.
# Which mailbox received the most customer email?
icp canister call backend execute '("{\"start\":\"message\",\"where\":{\"and\":[{\"eq\":{\"field\":\"direction\",\"value\":\"inbound\"}},{\"eq\":{\"field\":\"contactId.kind\",\"value\":\"customer\"}}]},\"groupBy\":[\"mailboxId\"],\"aggregate\":[{\"fn\":\"count\",\"as\":\"received\"}],\"orderBy\":[{\"field\":\"received\",\"dir\":\"desc\"}],\"limit\":5}")' --queryOpen Email is built to run on a customer's own OpenCloud engine. Once built, bundle and deploy it to the engine's subnet and tag the canisters so the engine console shows a named app with labelled backend/frontend canisters (the deploy-to-cloud-engine flow).
This project keeps a synced copy of the latest Internet Computer skills (.claude/skills/, refreshed by a SessionStart hook) and vendors the two OQL skills — using-oql and querying-oql — from caffeinelabs/oql-prototype, so any agent working here knows how to author and query OQL.
Stage 1 — demo-ready. Backend compiles and deploys; the frontend type-checks and builds; the corpus seeds; OQL queries and the AIware action layer are verified end-to-end against the deployed canister. See SPEC.md for the roadmap (live ingestion, sending, role-based OQL row filtering, vetKeys-encrypted bodies).