Skip to content

System Architecture

Serverless Inbox is built entirely on AWS serverless services. There are no persistent servers—all compute runs as on-demand Lambda functions, with DynamoDB as the primary data store and S3 for binary storage.

graph LR
Clients["Email clients<br/>Webmail UI"] -->|JMAP| JMAP["jmap-api λ"]
AdminUI["Admin UI"] -->|REST| Admin["admin-api λ"]
SES_IN["AWS SES"] -->|receipt rule| Ingest["email-processor λ"]
JMAP & Admin & Ingest --> DDB[("DynamoDB")]
JMAP & Admin & Ingest --> S3[("S3")]

Figure 1: The three entry points into the system: email clients via JMAP, admin operations via REST, and inbound email via SES.


ComponentTypePurpose
jmap-apiAPI LambdaJMAP protocol handler for email clients
admin-apiAPI LambdaTenant and user administration
email-processorEvent LambdaProcesses incoming email from SES
email-senderQueue LambdaSends outgoing email via SES
sqs-ses-event-processorQueue LambdaHandles SES delivery/bounce/complaint feedback
websocket-connect/disconnect/messageWebSocket LambdasManage client WebSocket connections
websocket-broadcastInternal LambdaPushes real-time notifications to connected clients
audit-writerQueue LambdaPersists audit events to DynamoDB
tantivy-indexerScheduled LambdaRebuilds full-text search indexes in S3
authorizerAuthorizer LambdaJWT validation for API Gateway
StoreContentsLifecycle
MailboxDataStack (Config, Item, Changelog, Audit Log, Mail Feedback tables + S3)Users, accounts, domains, IDPs, emails, threads, mailboxes, delivery feedback, search indexesRetained across mailbox stack redeploys
DynamoDB JWK cache tableCached OIDC public keysEphemeral—rebuilt on each deploy
DynamoDB WebSocket connections tableActive client push connectionsEphemeral—transient session state

No persistent servers. All compute is Lambda. There are no EC2 instances, containers, or processes to keep alive.

Real-time push via direct Lambda invocation. After writing to DynamoDB, the processing Lambda invokes websocket-broadcast directly. websocket-broadcast looks up active connections and pushes via API Gateway Management API. There is no message bus in this path.

Full-text search is a secondary feature. Simple mailbox queries (the vast majority) read DynamoDB directly. Tantivy is only used for complex text-search queries and runs as an in-process CGO library inside jmap-api, not as a separate service. See Search Architecture for details.

Separate data stack prevents lifecycle conflicts. The five retained DynamoDB tables and S3 bucket live in a separate CloudFormation stack that is never deleted when the mailbox stack is deleted. This enables safe deploy → delete → redeploy cycles without data loss or table recreation.