EMAIL is CyberOS's mail server, shared inbox, and AI-native composition surface in a single bundled module. The protocol stack is Stalwart (Rust, single binary) speaking JMAP / IMAP / SMTP / ManageSieve to the world. On top sits a Missive-style UX where a team can manage support@cyberskill.world together — assignment, internal comments, snooze, tagging. Every inbound body passes through a CaMeL quarantined LLM before any privileged CUO context can see it; the privileged side operates on the sanitised extraction (sender, recipient, subject, gist, action requests, entities), never on raw HTML. Outbound mail is DKIM-signed with per-tenant keys, ARC-stamped on forward, and tagged with BIMI for inbox-list branding. Threading is JMAP-native; search is PGroonga (Vietnamese-aware bigram); calendar is iCal. DSAR export bundles every message a subject participated in.
Why EMAIL exists
Three reasons to own the mail plane rather than outsource to a SaaS provider: (1) injection defence — most of the high-profile 2025 prompt-injection CVEs entered through email, and a hosted provider does not let you put a CaMeL quarantine between the body and the agent; (2) shared-inbox UX — teams managing support@, sales@, billing@ need assignment, internal comments, and snooze, which Gmail / M365 implement only via shaky third-party add-ons; (3) data residency — Vietnamese tenants under Decree 53 must keep certain customer data on Vietnamese soil, which most hosted mail providers cannot promise. Stalwart gives us a credible Rust mail server, a Missive-style UX gives us the shared-inbox primitive, and CaMeL gives us a proof-shaped boundary against indirect prompt injection.
Untrusted body → quarantined LLM (no tools, no memory) → structured extraction → privileged CUO. Never raw HTML into the agent's context window.
One address, many people. Assign a thread to a teammate. Comment internally without the customer seeing. Snooze until Monday. The Missive playbook.
PGroonga search handles VN bigram tokenisation; AI drafts respect Anh / Chị / Bạn salutations and TPHCM / Hà Nội regional sign-off conventions.
EchoLeak (CVE-2025-32711, May 2025) was the canonical demonstration: a malicious email tricked Microsoft 365 Copilot into exfiltrating data with zero user clicks. The attack class continued through April 2026. The lesson is not "patch the LLM" — it is "do not let the LLM see the raw body". CaMeL is the architecture that enforces that, and EMAIL is the module where that enforcement lives.
What it does — 5W1H2C5M
A structured decomposition of EMAIL's scope. Every cell traces back to PRD §9.4 and §11.2.3.
| Axis | Question | Answer |
|---|---|---|
| 5W · What | What is EMAIL? | A Stalwart-based mail server (JMAP / IMAP / SMTP / MTA-STS / DANE / DKIM / ARC / BIMI) plus a Missive-style shared-inbox UX, gated by a CaMeL dual-LLM filter on every inbound body. Single Rust deployment with a separate TypeScript SPA. Postgres for metadata; object storage (S3 + KMS) for bodies and attachments. |
| 5W · Who | Who uses it? | Members: personal inboxes + assigned shared inboxes. Customers: external senders / recipients (never authenticate to CyberOS). Agents: CUO via MCP for draft-reply / categorise / snooze tools. Owner: CCO seat (interim CEO). |
| 5W · When | When does it run? | Continuous SMTP listener (25 / 465 / 587). JMAP / IMAP for client sync. Inbound CaMeL scan runs on the receive path before any thread row is committed. Outbound DKIM signing happens at queue time. AI features (draft, summarise) run on user demand. |
| 5W · Where | Where does it run? | P1: single region (SG-1) plus a VN-residency relay for Decree 53 customers. P3+: multi-region with active-active SMTP and an MX-record failover. Object storage and Postgres are tenant-tagged; vn-residency=true tenants land on hanoi-1. |
| 5W · Why | Why own the plane? | Three reasons: (a) prompt-injection defence requires the CaMeL boundary, which a SaaS does not allow; (b) shared-inbox UX needs internal-comments and assignment primitives that Gmail does not provide natively; (c) Vietnamese data-residency obligations under Decree 53. |
| 1H · How | How does it work? | Inbound: SMTP → DKIM / SPF / DMARC verify → spam triage → CaMeL quarantined extraction → thread merge by JMAP threadId → notification fan-out. Outbound: composer → CaMeL out-bound scan (block PII leaks) → DKIM sign → MTA-STS / DANE next-hop → SMTP send. AI: composer pulls draft from AI Gateway with persona-stamped JWT. |
| 2C · Cost | Cost budget? | P1: ~$110 / month for SG-1 single-tenant pilot (Stalwart Fargate + RDS Postgres + S3 + Redis cache). 50-tenant: ~$420 / month. Per-message inbound CaMeL cost ~$0.0004 (gpt-4o-mini-equivalent extraction). |
| 2C · Constraints | Constraints? | (a) AGPL-3.0 — Stalwart's licence means our distribution model is service-only. (b) DMARC alignment mandatory — strict policy from M+3. (c) No body content into BRAIN by default ((FR pending)); opt-in per Member. (d) CaMeL on every ingest path — non-negotiable. |
| 5M · Materials | Stack? | Stalwart Mail Server (Rust) · axum HTTP API · sqlx · PostgreSQL 16 · PGroonga search · Redis 7 cache · S3 + KMS for bodies · CaMeL adapter on top of AI Gateway · OpenTelemetry SDK · React / TypeScript SPA · htmx + Alpine for the inbox shell. |
| 5M · Methods | Method choices? | JMAP-native threading (no Reply-To header heuristics). PGroonga over tsvector (Vietnamese bigram quality wins). CaMeL dual-LLM (quarantined no-tools + privileged). Per-tenant DKIM keypair stored in KMS. ARC stamping on forward. Single-binary Stalwart deployment (no separate MTA / MDA / MUA processes). |
| 5M · Machines | Deployment? | Fargate task per region for SMTP + JMAP + IMAP listeners. RDS Postgres for metadata. S3 + KMS for bodies and attachments. Redis for hot-thread cache. Per-tenant DKIM keypair in KMS. |
| 5M · Manpower | Who maintains? | 0.5 FTE (CTO seat) at P1 launch. By P2+: CCO seat owns product; CTO owns infra; CSO consulted on every Stalwart upgrade. |
| 5M · Measurement | How measured? | Deliverability (DMARC pass rate ≥ 98%), p95 send latency ≤ 2 s, p95 receive latency ≤ 5 s, CaMeL injection-block rate ≥ 99.5% on the test corpus, AI-draft acceptance ≥ 40% by Member. |
Architecture
EMAIL has four planes: the protocol plane (Stalwart, talking SMTP / IMAP / JMAP outbound and inbound to the world); the policy plane (CaMeL filter + DKIM / SPF / DMARC verify + per-tenant ACL); the UX plane (the Missive-style SPA + an htmx-light fallback for slow networks); and the AI plane (draft, summarise, categorise — all routed through AI Gateway with the privileged CUO persona). The diagram shows the canonical inbound path with the CaMeL boundary highlighted.
(any SMTP source)"] RECIPIENT["External recipient"] end subgraph EDGE ["Edge / protocol plane"] SMTP["📨 Stalwart SMTP
25 · 465 · 587"] JMAP["📡 Stalwart JMAP
/jmap/"] IMAP["📬 Stalwart IMAP
143 · 993"] MTA_STS["MTA-STS · DANE
next-hop policy"] end subgraph POLICY ["Policy plane"] DKIM_VERIFY["DKIM / SPF / DMARC
verify"] SPAM["Spam triage"] CAMEL["🛡 CaMeL quarantine
no-tools LLM"] EXTRACT["Sanitised extraction:
{from, to, subj, gist,
actions, entities}"] DKIM_SIGN["DKIM sign
per-tenant key (KMS)"] ARC["ARC stamp
on forward"] end subgraph CORE ["EMAIL service (Rust)"] THREAD["Thread merger
JMAP threadId"] INBOX["Shared-inbox
assignment · comments"] SEARCH["PGroonga search
(VN bigram)"] CAL["iCal · calendar"] SIEVE["ManageSieve
rules engine"] end subgraph STORES ["Stores"] PG[("PostgreSQL
threads · assignments
RLS by tenant_id")] S3[("S3 + KMS
bodies + attachments")] RED[("Redis 7
hot threads · search cache")] KMS_K[("AWS KMS
per-tenant DKIM keys")] end subgraph SINKS ["Sinks"] BRAIN["🧠 BRAIN
summaries (opt-in) ·
audit rows"] OBS["👁 OBS
traces + DMARC reports"] CUO["🎯 CUO
privileged agent"] AI["⚡ AI Gateway"] end SENDER --> SMTP SMTP --> DKIM_VERIFY DKIM_VERIFY --> SPAM SPAM --> CAMEL CAMEL --> EXTRACT EXTRACT --> THREAD THREAD --> PG THREAD --> S3 THREAD --> SEARCH THREAD --> BRAIN THREAD --> INBOX THREAD --> RED INBOX --> CUO CUO --> AI AI --> CAMEL CAMEL --> AI JMAP --> THREAD IMAP --> THREAD SIEVE --> THREAD CAL --> THREAD THREAD --> DKIM_SIGN DKIM_SIGN --> KMS_K DKIM_SIGN --> ARC ARC --> MTA_STS MTA_STS --> RECIPIENT THREAD --> OBS classDef planned fill:#e2e8f0,stroke:#334155 classDef store fill:#f5f3ff,stroke:#7c3aed classDef sink fill:#f5ede6,stroke:#45210e classDef camel fill:#fee2e2,stroke:#b91c1c,stroke-width:3px class SMTP,JMAP,IMAP,MTA_STS,THREAD,INBOX,SEARCH,CAL,SIEVE,DKIM_VERIFY,SPAM,DKIM_SIGN,ARC planned class CAMEL,EXTRACT camel class PG,S3,RED,KMS_K store class BRAIN,OBS,CUO,AI sink
Internal components
| Component | Path (planned) | Responsibility |
|---|---|---|
stalwart_adapter.rs | services/email/src/stalwart_adapter.rs | Spawns and supervises the Stalwart binary; bridges its event stream into the rest of CyberOS. |
camel.rs | services/email/src/camel.rs | CaMeL boundary. Calls the quarantined LLM through AI Gateway with persona=quarantined-extractor (no tools, no memory). Returns the sanitised structured extraction. |
dkim_verify.rs | services/email/src/dkim_verify.rs | Inbound DKIM / SPF / DMARC verification. Wraps mail-auth crate. |
dkim_sign.rs | services/email/src/dkim_sign.rs | Outbound DKIM signing with per-tenant key from KMS. ARC stamping on forward. |
thread.rs | services/email/src/thread.rs | Thread merge using JMAP-native threadId. Reply-To / In-Reply-To / References headers as inputs; never used as authoritative thread keys. |
inbox.rs | services/email/src/inbox.rs | Shared-inbox state — assignment, comments, snooze, tags. RLS-keyed by inbox_id. |
search.rs | services/email/src/search.rs | PGroonga query builder with Vietnamese bigram tokenisation. Falls back to tsvector for non-CJK locales. |
sieve.rs | services/email/src/sieve.rs | ManageSieve rules engine — per-Member auto-tag, auto-snooze, auto-route. Rules compiled to Stalwart's sieve runtime. |
ical.rs | services/email/src/ical.rs | iCal parser / generator. Calendar invites surface as native events in CyberOS Calendar. |
draft_ai.rs | services/email/src/draft_ai.rs | AI-suggested-reply pipeline. Pulls from AI Gateway; persona-stamped; CyberSkill voice; Vietnamese-aware salutation logic. |
brain_summariser.rs | services/email/src/brain_summariser.rs | Per-thread summary writer. Calls AI Gateway in summarise mode; writes a single BRAIN row per thread with citations back to message IDs. Body bytes never enter BRAIN by default ((FR pending)). |
dmarc_report.rs | services/email/src/dmarc_report.rs | Aggregate DMARC RUA / RUF reports per tenant; surface to Trust Center ((FR pending)). |
dsar_export.rs | services/email/src/dsar_export.rs | DSAR bundle: every message a subject participated in, with attachments and decisions. |
migration_import.rs | services/email/src/migration_import.rs | Gmail / M365 / IMAP import. Walks the source via JMAP / IMAP, replays threads in CaMeL-filtered order, writes audit row per imported message. |
migrations/ | services/email/migrations/ | sqlx migrations. All identity-touching tables RLS-keyed by tenant_id; shared-inbox tables additionally RLS-keyed by inbox_id. |
Data model
Metadata lives in PostgreSQL with row-level security keyed by tenant_id; bodies and attachments live in S3 + KMS, addressed by content-hash. Threads are normalised on JMAP threadId, not on Reply-To header heuristics. Shared inboxes are a separate table with their own ACL; a Member can be a participant in many inboxes, and an inbox can be managed by many Members.
Indexing & search strategy
- Threads indexed on
(tenant_id, mailbox_id, last_message_at DESC)and(inbox_id, status, last_message_at DESC)for shared-inbox views. - Messages have a PGroonga index on
subject || coalesce(camel_extraction.gist, '')— body bytes are never indexed; the CaMeL gist is the queryable surface. - Attachments are content-addressed by sha256; an antivirus daemon (ClamAV) marks
scanned=true; unscanned attachments are quarantined and not downloadable. - DKIM keys rotate every 90 days; old selectors retained 30 days for verification of recently received forwards.
- RLS: every table enforces
WHERE tenant_id = current_setting('cyberos.tenant_id')::uuid; shared-inbox tables additionally enforce inbox-participation membership.
API surface
Four surfaces: JMAP for IETF-standard mail clients, a GraphQL federated subgraph for the CyberOS SPA, MCP tools for the CUO agent, and a small REST admin surface for DKIM rotation and Trust-Center reports.
GraphQL subgraph (federated)
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@key", "@requiresScopes"])
type Mailbox @key(fields: "id") {
id: ID!
address: String!
displayName: String!
kind: MailboxKind!
unread: Int!
threads(status: ThreadStatus, limit: Int = 50, cursor: String): ThreadConnection!
@requiresScopes(scopes: [["email.read"]])
}
type SharedInbox @key(fields: "id") {
id: ID!
address: String!
displayName: String!
defaultAssignee: Subject
unassignedCount: Int!
threads(status: ThreadStatus, assignee: ID, limit: Int = 50): ThreadConnection!
@requiresScopes(scopes: [["email.shared.read"]])
}
type Thread @key(fields: "id") {
id: ID!
subject: String!
participants: [String!]!
messageCount: Int!
lastMessageAt: DateTime!
status: ThreadStatus!
assignment: Assignment
tags: [String!]!
comments: [InternalComment!]!
summary: AISummary
messages(limit: Int = 50): [Message!]!
}
type Message @key(fields: "id") {
id: ID!
from: String!
to: [String!]!
cc: [String!]
subject: String!
receivedAt: DateTime!
bodyPreview: String! # CaMeL gist · NOT raw body
attachments: [Attachment!]!
dmarc: DMARCResult!
}
type AISummary {
threadId: ID!
summary: String!
citations: [Citation!]!
generatedAt: DateTime!
}
enum MailboxKind { PERSONAL SHARED }
enum ThreadStatus { ACTIVE SNOOZED DONE }
enum DMARCResult { PASS FAIL NONE }
type Mutation {
assignThread(threadId: ID!, assigneeId: ID!): Boolean!
@requiresScopes(scopes: [["email.shared.assign"]])
snoozeThread(threadId: ID!, until: DateTime!): Boolean!
resolveThread(threadId: ID!): Boolean!
addInternalComment(threadId: ID!, body: String!): InternalComment!
draftReply(threadId: ID!, intent: ReplyIntent): DraftReplyResult!
@requiresScopes(scopes: [["email.compose"]])
sendMessage(input: SendMessageInput!): Message!
@requiresScopes(scopes: [["email.send"]])
}
REST + admin surface
| Method | Path | Purpose |
|---|---|---|
| GET | /.well-known/mta-sts.txt | MTA-STS policy. |
| GET | /jmap/ | JMAP entry point (RFC 8620). |
| POST | /jmap/api/ | JMAP method calls. |
| POST | /jmap/upload/ | JMAP blob upload. |
| GET / POST | /imap/ | IMAP IDLE / fetch (port 993). |
| SMTP | :25 / :465 / :587 | Submission and inter-MTA relay. |
| POST | /admin/dkim/rotate | Rotate per-tenant DKIM keypair; old selector retained 30 d. |
| GET | /admin/dmarc/reports | DMARC aggregate report list. |
| POST | /admin/shared-inbox/create | Create a shared inbox. |
| POST | /admin/shared-inbox/{id}/participants | Add / remove participants. |
| POST | /admin/sieve/{mailbox_id} | Install a ManageSieve script. |
| POST | /admin/import/start | Start Gmail / M365 / IMAP migration. |
| GET | /admin/import/{job_id}/status | Migration progress. |
| POST | /admin/dsar/export | Generate DSAR bundle for a subject. |
MCP tool catalogue
| Tool name | Inputs | Outputs | Annotations |
|---|---|---|---|
cyberos.email.list_threads | mailbox_id?, inbox_id?, status?, limit | Thread[] | readonly · scope=email.read |
cyberos.email.read_thread | thread_id | Thread + Messages (gist only) | readonly |
cyberos.email.draft_reply | thread_id, intent | {draft_text, tone, language} | readonly |
cyberos.email.send | SendMessageInput | {message_id} | destructive · human-confirm · scope=email.send |
cyberos.email.assign_thread | thread_id, assignee_id | {ok} | scope=email.shared.assign |
cyberos.email.snooze | thread_id, until | {ok} | scope=email.compose |
cyberos.email.promote_to_proj | thread_id, project_id | {issue_id} | scope=proj.write |
cyberos.email.summarise_thread | thread_id | {summary, citations} | readonly |
Key flows
Flow 1 — Inbound message with CaMeL scan
NO tools, NO memory,
NO BRAIN access Q-->>ST: {gist, action_requests, entities, injection_flag} ST->>T: merge by jmap_thread_id T->>PG: insert message + camel_extraction row T->>B: append email.inbound {actor:sender, decision:"received", camel_flag} T-->>U: WebSocket push: new message preview (gist only) Note over U: SPA renders gist + redacted body;
user can click "show raw" → fetches HTML
with sandbox iframe; raw never enters CUO context
If injection_flag is set, the message is flagged in the UI with a banner and the AI-draft-reply tool refuses to run on that thread.
Flow 2 — Outbound message with DKIM signing
Flow 3 — AI-drafted reply (CyberSkill voice, Vietnamese-aware)
only the CaMeL gist + structured fields API->>CU: compose({gist, intent, voice:"cyberskill", language:"vi"}) CU->>AG: chat.completions (persona-stamped JWT, vi salutation rules) AG-->>CU: draft text CU-->>API: draft + tone notes API->>B: email.draft_generated {thread, model, persona_version} API-->>U: {draft, tone:"warm", salutation:"Chào Anh / Chị"} Note over U: Member edits, then sends via Flow 2
Vietnamese salutation logic: the extracted entities include the recipient's likely gender / title; if confidence < 0.7, the draft defaults to neutral "Chào Anh/Chị".
Flow 4 — Shared-inbox assignment
Flow 5 — Gmail → CyberOS migration
Injection-flagged historical messages are tagged but not deleted; the AI-draft tool refuses to operate on them, and a UI banner explains the flag.
Message lifecycle
Inbound and outbound messages traverse separate state machines, but every state transition emits a BRAIN audit row.
Outbound state machine
| State | Transition | Audit row |
|---|---|---|
composing | draft saved every 10 s | — |
outbound_scan | CaMeL out-bound PII / secret detection | email.outbound_scan |
queued | signed, in Stalwart queue | email.outbound_queued |
relayed | MX SMTP 250 received | email.outbound_relayed |
delivered | DSN MDN received (if requested) | email.outbound_delivered |
bounced | permanent 5xx from MX | email.outbound_bounced |
deferred | 4xx — retry per backoff | email.outbound_deferred |
Functional Requirements
The CyberOS FR catalogue is being rebuilt one feature at a time via the open fr-author Agent Skill.
Previous FR enumerations were archived 2026-05-14 and are no longer reflected on this page. PRD/SRS narrative remains authoritative for the spec; specific FRs land here as they are re-authored.
Non-Functional Requirements
PRD §11.2 NFRs that EMAIL must satisfy. Cross-referenced at nfr-catalog.html#email.
| NFR ID | Concern | Target | Measurement |
|---|---|---|---|
N(FR pending) | Inbound message → thread visible to recipient | p95 ≤ 5 s | k6 SMTP-to-UI test · nightly |
N(FR pending) | Outbound message accepted to relay | p95 ≤ 2 s | k6 send-loop · nightly |
N(FR pending) | CaMeL extraction latency | p95 ≤ 1.2 s | AI Gateway histogram |
N(FR pending) | Thread list page load (50 threads) | p95 ≤ 350 ms | SPA RUM |
N(FR pending) | Outbound DMARC pass rate | ≥ 99% of attempted | weekly DMARC aggregate |
N(FR pending) | Inbound deliverability (Tier-1 MX accept rate) | ≥ 99.5% | SMTP 250-OK ratio |
N(FR pending) | SMTP-receive availability (28-day) | ≥ 99.9% | OBS SLO monitor |
N(FR pending) | CaMeL injection-block rate on red-team corpus | ≥ 99.5% | monthly red-team replay |
N(FR pending) | Body bytes in BRAIN without opt-in | = 0 | CI gate on BRAIN ingestion paths |
N(FR pending) | Message durability after acceptance | 0 lost messages under crash | chaos test · BRAIN ledger walk |
N(FR pending) | AI-draft acceptance rate | ≥ 40% by Member | SPA telemetry |
N(FR pending) | Shared-inbox first-response time | p50 ≤ 30 min business hours | BRAIN assignment events |
N(FR pending) | VN-residency tenant message storage region | 100% hanoi-1 | S3 key-prefix audit |
Dependencies
EMAIL leans on AUTH (every JMAP / GraphQL call), BRAIN (audit + opt-in summary), AI (CaMeL extraction + draft generation), MCP (CUO tools), and OBS (DMARC reports + traces). It is leaned on by CRM (activity auto-log), PROJ ("promote to task"), CUO (assignment categoriser), and KB (publishing a doc as an email digest).
OAuth · RBAC"] BRAIN["🧠 BRAIN
audit + opt-in summary"] AI["⚡ AI Gateway
CaMeL + draft"] MCP["🔌 MCP
CUO tools"] OBS["👁 OBS
traces + DMARC"] STALWART["📦 Stalwart
(vendored Rust)"] KMS["🔑 KMS
DKIM keys"] S3["🗄 S3
bodies + attachments"] end EMAIL["✉️ EMAIL"] subgraph downstream ["EMAIL is depended on by"] CRM["🤝 CRM
email→activity"] PROJ["📋 PROJ
thread→issue"] CUO["🎯 CUO
shared-inbox classifier"] KB["📚 KB
email digests"] PORTAL["Portal · P2"] end AUTH --> EMAIL BRAIN --> EMAIL AI --> EMAIL MCP --> EMAIL OBS --> EMAIL STALWART --> EMAIL KMS --> EMAIL S3 --> EMAIL EMAIL --> CRM EMAIL --> PROJ EMAIL --> CUO EMAIL --> KB EMAIL --> PORTAL classDef shipped fill:#f5ede6,stroke:#45210e classDef planned fill:#fef6e0,stroke:#9c750a class BRAIN,STALWART,KMS,S3 shipped class EMAIL,AUTH,AI,MCP,OBS,CRM,PROJ,CUO,KB,PORTAL planned
Compliance scope
Email is a magnet for regulators. EMAIL must satisfy PDPL, GDPR, RFC compliance, and Decree-13 personal data processing log requirements.
| Regulation / standard | Article / clause | EMAIL feature that satisfies it |
|---|---|---|
| Vietnam PDPL (Law 91/2025) | Art. 14 — DSAR | cyberos-email dsar-export bundles every message a subject sent / received. |
| Vietnam Decree 13/2023 | Art. 17 — Personal data processing log | Every inbound / outbound writes a BRAIN audit row. |
| Vietnam Decree 53/2022 | Art. 26 — Data localisation | Per-tenant vn_residency flag routes bodies + attachments to hanoi-1 S3. |
| GDPR (EU 2016/679) | Art. 15 — Right of access | DSAR export. |
| GDPR | Art. 17 — Right to erasure | Soft-delete + 30-day purge; DSAR-driven hard purge. |
| GDPR | Art. 32 — Security of processing | TLS 1.3 SMTP, KMS-wrapped bodies, RLS, DKIM signing. |
| RFC 5322 | Internet Message Format | Stalwart parser is RFC-compliant; canonical headers preserved. |
| RFC 6376 | DKIM Signatures | dkim_sign.rs + per-tenant KMS key. |
| RFC 7208 | SPF | Inbound verifier; outbound DNS check. |
| RFC 7489 | DMARC | Inbound enforcement; aggregate report ingestion. |
| RFC 8460 | SMTP TLS reporting | Stalwart TLSRPT support; ingested into OBS. |
| RFC 8461 | MTA-STS | Outbound policy fetch; inbound policy publication. |
| RFC 8617 | ARC | ARC stamping on forward. |
| RFC 8620 | JMAP | Native JMAP server via Stalwart. |
| BIMI v1 | Brand Indicators | VMC + SVG-Tiny logo serving on opt-in tenants. |
| OWASP Gen AI Top-10 (2025) | LLM01: Prompt Injection | CaMeL dual-LLM is the canonical mitigation. |
Risk entries
EMAIL carries the second-highest single-module risk weight after AUTH; injection attacks here propagate to every downstream module. Tracked in the risk register.
| ID | Risk | Likelihood | Impact | Owner | Mitigation |
|---|---|---|---|---|---|
R-EMAIL-001 | CaMeL bypass via novel injection technique | Medium | Catastrophic | CSO | Red-team corpus refreshed monthly; quarantined LLM has zero tools; CUO never sees raw body even on bypass. |
R-EMAIL-002 | Stalwart CVE landing zero-day | Medium | High | CTO | Subscribe to security advisories; auto-PR + canary test on patch release; rollback plan documented. |
R-EMAIL-003 | DKIM key compromise → spoofing tenant | Low | High | CSO | KMS-wrapped; rotation every 90 d; old selector retained 30 d. |
R-EMAIL-004 | Outbound spam reputation collapse → IP block | Medium | High | CTO | Per-tenant send rate limits; warm-up plan; SubMTA / dedicated IP at P2+; Postmaster Tools monitoring. |
R-EMAIL-005 | Body-content leak into BRAIN via misconfigured rule | Low | High | CDO | Static-analysis CI gate on every BRAIN-ingestion code path; canonical ingestion is summary-only. |
R-EMAIL-006 | VN-residency tenant body lands in non-VN S3 | Low | High | CCO | S3 key-prefix audit nightly; failure pages CSO. |
R-EMAIL-007 | Attachment with malware reaches user (AV bypass) | Medium | Medium | CSO | ClamAV + heuristic scan; "show raw" view in sandbox iframe; user banner for unscanned attachments. |
R-EMAIL-008 | JMAP / IMAP credential leak via SPA bug | Low | High | CTO | OAuth 2.1 access tokens only; no IMAP password reuse; refresh-token rotation. |
R-EMAIL-009 | Migration import overflows quarantine review queue | Medium | Low | CTO | Rate-limited import (1k msg / min); injection-flagged messages tagged but not blocking the import. |
R-EMAIL-010 | AGPL-3.0 obligations on Stalwart redistribution | Medium | Medium | CLO | Service-only distribution; source-code-offer URL on Trust Center; legal review of every Stalwart fork. |
KPIs
EMAIL health rolls up into 10 KPIs covering deliverability, injection-defence efficacy, AI-feature quality, and shared-inbox UX.
| KPI | Formula | Source | Target |
|---|---|---|---|
| Outbound DMARC pass rate | dmarc.pass / dmarc.total | weekly aggregate | ≥ 99% |
| Inbound deliverability | 250_ok / smtp_attempts | Stalwart logs | ≥ 99.5% |
| CaMeL injection-block rate | blocked / red_team_corpus | monthly red-team | ≥ 99.5% |
| CaMeL extraction p95 | histogram | OBS | ≤ 1.2 s |
| AI-draft acceptance rate | drafts_sent / drafts_offered | SPA telemetry | ≥ 40% |
| Shared-inbox first-response p50 | median minutes | BRAIN assignment events | ≤ 30 min (BH) |
| Snooze usage | snoozes / Member / week | SPA telemetry | tracked |
| Spam false-positive rate | fp / total_classified_spam | user "not spam" actions | ≤ 0.5% |
| Outbound CaMeL block rate | blocked / sent attempts | BRAIN | tracked; alert on > 1% / day |
| Attachment AV-quarantine rate | quarantined / total | BRAIN | tracked; alert spike |
RACI matrix
EMAIL is owned by the CCO seat. Today (CCO vacant), the CEO is interim accountable; the CTO owns engineering; the CSO is consulted on every CaMeL-touching change.
| Activity | CEO | CTO | CSO | CCO | CDO | CLO |
|---|---|---|---|---|---|---|
| Service design + spec | A | R | C | C | I | C |
| Implementation | I | A/R | C | I | I | I |
| CaMeL boundary review | I | C | A/R | I | C | I |
| Stalwart upgrade | I | A/R | R | I | I | C |
| DKIM key rotation | I | R | A | I | I | I |
| DMARC policy authoring | C | R | A | I | I | C |
| Shared-inbox product | C | C | I | A/R | I | I |
| DSAR fulfilment | I | C | C | I | R | A |
| Trust Center publication | C | C | C | R | I | A |
| AGPL compliance review | I | C | I | I | I | A/R |
R Responsible · A Accountable · C Consulted · I Informed.
Planned CLI surface
A single admin CLI cyberos-email for tenant operators. Destructive commands always write a chained audit row before exit.
1. Create a shared inbox
$ cyberos-email shared-inbox create \
--tenant cyberskill \
--address support@cyberskill.world \
--display "CyberSkill Support" \
--default-assignee linh@cyberskill.world
[shared-inbox created]
id: 01HZK1Y2J3K4M5N6P7Q8R9S0T1
address: support@cyberskill.world
audit: brain seq=14902 chain=1a2b…3c4d
2. Rotate per-tenant DKIM key
$ cyberos-email dkim rotate --tenant cyberskill --reason "quarterly-scheduled"
[rotate] new selector: cyberos-2026-q2
[kms] old selector cyberos-2026-q1 retained for verification (30 d)
[dns] _domainkey.cyberskill.world TXT record updated
[audit] brain seq=14905 chain=5d6e…7f80
3. Import from Gmail
$ cyberos-email import gmail \
--user stephen@cyberskill.world \
--since 2024-01-01 \
--rate-limit 1000/min
[import] authenticating via XOAUTH2 …
[import] selecting [Gmail]/All Mail … 12,481 messages
[import] walking threads (CaMeL extracting on the fly) …
[import] complete · 12,481 messages · 47 injection-flagged · 0 errors
[audit] brain seq=14952 chain=9a8b…7c6d
4. View DMARC aggregate report
$ cyberos-email dmarc report --tenant cyberskill --since 7d
domain policy sent pass fail pct
cyberskill.world reject 8,213 8,201 12 99.85%
↳ google.com - 4,102 4,098 4 99.90%
↳ outlook.com - 2,108 2,103 5 99.76%
↳ proton.me - 1,003 1,000 3 99.70%
↳ other - 1,000 1,000 0 100.00%
5. Run CaMeL red-team replay
$ cyberos-email redteam replay --corpus echoleak-v3 --output report.json
[replay] corpus: echoleak-v3 (412 messages)
[replay] running quarantined extraction …
[replay] ✓ 410 / 412 injection attempts blocked (99.51%)
[replay] ✗ 2 escapes — see report.json#escapes
[audit] brain seq=14958 chain=ef01…2345
6. Export DSAR bundle
$ cyberos-email dsar-export --subject stephen@cyberskill.world --output stephen.zip
[dsar] subject: stephen@cyberskill.world
[dsar] threads: 1,247
[dsar] messages: 8,213 (3,142 inbound · 5,071 outbound)
[dsar] attachments: 412 (412 MB)
[dsar] summaries: 1,247 (CaMeL gist)
[dsar] written: stephen.zip (478 MB)
[audit] brain seq=14961 chain=6a7b…8c9d
7. Install ManageSieve rule
$ cyberos-email sieve install --mailbox stephen@cyberskill.world --file my.sieve
require ["fileinto", "imap4flags"];
if address :is "from" "noreply@github.com" {
fileinto "GitHub";
setflag "\\Seen";
stop;
}
[sieve] parsed · 1 rule
[sieve] installed at priority 100
[audit] brain seq=14963 chain=2b3c…4d5e
Phase status & estimates
cyberos-email| Capability | Status |
|---|---|
| Stalwart core (SMTP / JMAP / IMAP) | planned · P1 |
| CaMeL quarantined extraction | planned · P1 |
| Per-tenant DKIM signing | planned · P1 |
| Shared inbox + assignment | planned · P1 |
| Internal-comments on threads | planned · P1 |
| AI-drafted reply (VN salutations) | planned · P1 |
| PGroonga Vietnamese search | planned · P1 |
| ManageSieve rule engine | planned · P1 |
| Gmail / M365 / IMAP import | planned · P1 |
| iCal calendar invite parsing | planned · P1 |
| DMARC aggregate reporting | planned · P1 |
| DSAR export bundle | planned · P1 |
| BIMI logo serving (VMC) | planned · P2+ |
| Dedicated SubMTA / reputation IP | planned · P2+ |
| Outbound encryption (S/MIME / PGP) | planned · P3+ |
| Multi-region active-active | planned · P3+ |
References
- PRD §9.4 — EMAIL strategy: Stalwart + Missive-style UX + CaMeL.
- PRD §11.2.3 — Security NFRs that EMAIL must satisfy.
- SRS §4.4 — Formal (FR pending) through (FR pending) with verification methods.
- Stalwart Mail Server —
github.com/stalwartlabs/mail-server(AGPL-3.0). - CaMeL paper — Google DeepMind, May 2025; "Defending LLM agents against prompt injection via privilege separation".
- EchoLeak (CVE-2025-32711) — May 2025 advisory on M365 Copilot prompt-injection exfiltration.
- RFC 5322 — Internet Message Format.
- RFC 6376 — DomainKeys Identified Mail (DKIM) Signatures.
- RFC 7208 — Sender Policy Framework (SPF).
- RFC 7489 — Domain-based Message Authentication, Reporting, and Conformance (DMARC).
- RFC 8460 — SMTP TLS Reporting.
- RFC 8461 — SMTP MTA Strict Transport Security (MTA-STS).
- RFC 8617 — Authenticated Received Chain (ARC).
- RFC 8620 — JSON Meta Application Protocol (JMAP).
- Decree 53/2022/NĐ-CP (Vietnam) — Cybersecurity Law; data residency.
- Decree 13/2023/NĐ-CP (Vietnam) — Personal data processing protection.
- Law 91/2025/QH15 (Vietnam PDPL) — Personal Data Protection Law.
- BIMI v1 — Brand Indicators for Message Identification.
- Architecture context: infrastructure.html#email.