Browse

Mail backend

Mail backend

Everlock's mail path runs across four crates:

  • mail-storage — primitive owning the on-disk schema, domain registry, and MailEventBus
  • backend-mail-smtp + frontend-smtp — inbound SMTP, authenticated submission, rules.toml evaluation, DKIM, forwarding
  • backend-mail-imap + frontend-imap — IMAPS / STARTTLS access on top of the same versioned store

Both mail backends share one versioned store (default everlock-mail) and one MailEventBus. Messages delivered over SMTP appear over IMAP within seconds, and IMAP IDLE clients receive untagged EXISTS notifications when new mail arrives.

What it does

  • receives inbound SMTP mail
  • evaluates rules.toml
  • stores raw .eml messages plus .toml sidecars in versioned storage
  • forwards mail through direct outbound SMTP with MX lookup
  • serves IMAPS on port 993 for standard mail clients (Thunderbird, Apple Mail, K-9 Mail, Outlook)
  • publishes _imaps._tcp and _submission._tcp SRV records so clients can autoconfigure from just an email address

How it fits in the system

The SMTP frontend owns:

  • SMTP connection state
  • STARTTLS
  • SMTP reply codes
  • ACME certificate lifecycle for mail.<domain>
  • per-recipient backend handoff

The SMTP backend owns:

  • rules.toml
  • mail storage writes for inbound and submission paths
  • DKIM signing
  • forwarding and retry behavior

The IMAP backend owns:

  • mailbox state (mailbox.toml with next_uid + uidvalidity)
  • folder filtering (folder is a sidecar tag, not a path component)
  • mailbox-mutation atomicity (one versioned-storage commit per IMAP command)
  • the ImapMailAccess trait registered for frontend-imap

The IMAP frontend owns:

  • the IMAP wire protocol (RFC 3501, plus IDLE / NAMESPACE / UIDPLUS / MOVE / SPECIAL-USE)
  • IMAPS on port 993, optional STARTTLS on 143
  • session state machine and per-session caches
  • TLS certificate reuse from the SMTP frontend (no separate ACME)

Rules are evaluated by ascending priority. Lower numbers run first, higher numbers run later, and omitted priority values default to 10. If two rules share the same priority, Everlock keeps file order as the tie-breaker.

Each rule has a direction field — inbound (default) or outbound. Inbound rules apply when mail arrives over SMTP. Outbound rules apply when mail is sent through the authenticated submission listener. Outbound rules are restricted to reject, drop, and forward actions.

Inbound SMTP also has an explicit hosted-domain model:

  • if no mail domains are configured yet, Everlock starts in a bootstrap mode and accepts syntactically valid recipients for setup convenience
  • once at least one mail domain is configured, inbound accepts only those configured local domains
  • this bootstrap mode is not a general relay mode

Submission is a separate SMTP listener:

  • it is intended for mail clients
  • it runs on a separate port
  • it requires authentication by default
  • sender authorization is tied to Everlock access grants

Mail storage is versioned and shared between SMTP and IMAP. The default shape is:

data/everlock-mail/
  rules.toml
  domains/
    example.com.toml
  example.com/
    alice/
      mailbox.toml
      2026/
        05/
          msg-1.eml
          msg-1.toml
          msg-2.eml
          msg-2.toml

The mailbox.toml file holds two scalars — next_uid (monotonic, never reused after EXPUNGE / MOVE) and uidvalidity (set once at mailbox creation). The UID is encoded in the filename so UID FETCH 42 is a direct path lookup.

The folder name (inbox, sent, drafts, trash, junk, or a custom name from a rule) lives in the .toml sidecar, not in the path. The five standard folders are advertised by RFC 6154 SPECIAL-USE attributes so mail clients identify them by role, not by name.

Quick start

Start the full mail stack (SMTP + IMAP) with explicit flags:

everlock serve \
  --frontend-smtp --backend-mail-smtp \
  --backend-mail-imap --frontend-imap

Or enable individual modules at runtime:

/backends enable mail-smtp
/backends enable mail-imap
/frontends enable imap

Sub-pages

  • Getting started: Inbound mail — start inbound SMTP, add rules.toml, send a hello-world inbound message, and inspect the stored mail
  • Getting started: Outbound mail — enable the submission port, create a sender domain, grant a mailbox, and send mail through authenticated SMTP
  • Getting started: IMAP access — enable the IMAP backend and frontend, set a user password, verify SRV autoconfiguration, connect Thunderbird / Apple Mail / K-9 Mail
  • Mail rules reference — complete reference for rules.toml: all match fields, all actions, priority semantics, inbound and outbound direction
  • Mail rules cookbook — ready-to-use patterns for common setups: domain restrictions, aliases, forwarding, spam blocking, and more

What is still missing

Mail is usable as a full inbound + outbound + IMAP stack today. Remaining deferred work:

  • webmail / HTTP read path
  • server-side SEARCH (clients fall back to local index)
  • CONDSTORE / QRESYNC sync-efficiency extensions
  • persistent retry queue across restarts
  • per-mailbox quotas

Read next