Reference

Architecture

How imbox is put together: the pieces, how mail gets in, how a request is handled, and where each secret lives.

imbox docs

This page is for people who want to understand imbox before they change it, or before they trust it. It describes what runs, where data lives, and how a message travels from your mail provider to your screen.

The pieces

imbox is one Node.js server and one PostgreSQL database. A reverse proxy in front adds HTTPS. Nothing else is needed.

Loading diagram...
PieceWhat it does
Web appA React app. The desktop and the phone are separate sets of screens, not one squeezed layout. The desktop app is the same web app in a native window, loaded from your server.
APIA Hono app. It answers the web app, the extension and agent keys, and serves the built web app.
Background jobRuns once a minute inside the same process. It syncs mail, sends scheduled messages, brings back bubbled-up threads and runs agents.
PostgreSQLHolds everything: mail, contacts, decisions, settings, sessions, encrypted secrets.
Live eventsA long-lived GET /api/events stream. PostgreSQL tells the server when threads change, and the server tells each open tab.
CaddyGets certificates and passes requests to the app. On a script install it also routes /docs to the docs site.

How a message arrives

Every route into imbox ends in the same place: storing the message, then deciding what its thread and sender mean.

Loading diagram...
  • Sync is a pull. Each minute, the job asks every connected mailbox what is new. A first connection imports nothing from the past.
  • Cleaning happens on arrival. Tracking pixels are removed when the message is stored. Remote images stay on the sender's server until you allow them.
  • The decision belongs to the sender, not the message. Once you let someone in, every later message follows that choice, across all your mailboxes.
  • Attachments are not stored in bulk. Message text and metadata are in the database. Files are fetched from the provider when you open them.

How a request is handled

Loading diagram...

Three kinds of caller reach the API, each with its own narrow door:

CallerCredentialWhat it can reach
The web and desktop appSession cookie imbox_session, 30 daysEverything the owner can do
The browser extensionToken imx_...Seven read and triage endpoints
An outside agentKey hfa_..., per mailboxOnly that mailbox, under /agent/v1

State-changing requests made with the cookie must carry an Origin that matches the app's address. Every route that takes an id checks that the row belongs to the signed-in user. The details are in API.

What the background job does

The job is a list of independent steps, run one after another. Each has a time budget and a hard deadline, and only one run of each at a time. One stuck step never stops the others, and a failed or slow step leaves a line in the log, such as job mail-sync error.

StepWhat it does
Mail syncPulls new mail from each mailbox
Scheduled sendsSends messages whose time has come
Bubble upsBrings threads back at the time you picked
Calendar syncUpdates Google and CalDAV calendars
Auto agentsLets agents read new mail and write replies
Agent webhooksTells outside agents that mail arrived
Vacation noticesSends away notices
Push and cleanupWeb push notices, and removing old rows

Long work lives here and never inside a web request, so a slow provider can't make the app feel slow. With more than one web process, a single coordinator runs the job. See a busier server.

Where the data lives

One PostgreSQL database and plain SQL. The only extension it uses is pg_trgm, for fast search. The rough shape:

Loading diagram...
  • Migrations only add tables and columns, and run once each at start-up. That is why an older release still works on a newer database. See Database.
  • Secrets are encrypted with SESSION_SECRET: mailbox passwords, AI keys, app secrets and two-factor secrets. Passwords and session tokens are stored as hashes. See Security and encryption for what is and is not encrypted.

Where AI fits

AI is optional and only runs when asked. The server calls your provider with your key. Nothing else in imbox depends on it.

Loading diagram...

Mail is treated as untrusted input. After the assistant has read mail, code holds back risky actions, whatever the model says. See AI assistant and Agents in the app.

Safety boundaries

  • Outbound requests go through a timeout and a destination check, so a user-supplied address can't reach your private network.
  • Cookie requests are checked for origin. Extension tokens and agent keys never use the cookie.
  • Passkeys, two-factor and lockout protect sign-in. Five failed logins lock it for 15 minutes.
  • One owner. There are no shared accounts, so there is no per-team permission model to get wrong.

Where to go next

  • Self-hosting: how this is laid out on a server.
  • Development: where each piece lives in the repository.
  • API: the endpoints and the three kinds of credentials.