# Limristem eMail Architecture

Limristem eMail targets Debian 13+ and combines standard mail components with a small REST control plane and optional multi-node topology.

## Components

| Component | Role |
|-----------|------|
| **Postfix** | SMTP ingress/egress, virtual maps via MariaDB, LMTP to Dovecot, Rspamd milter, optional SRS (`postsrsd`) |
| **Dovecot** | IMAP/POP3/LMTP, SQL userdb, Maildir, quota; **checkpassword** for primary + app passwords |
| **Rspamd + Redis** | Spam scoring, DKIM signing, ARC, greylist, Bayes; per-user **send rate** soft-reject via Lua |
| **MariaDB** | Domains, accounts, aliases, redirects, MFA, app passwords, topology, traffic stats, reputation |
| **PostSRSd** | Envelope rewriting for external redirects (SPF-friendly) |
| **FastAPI** | Control plane: CRUD, DKIM/DNS, ops, stats, topology, auth/MFA, panel |
| **Nginx** | HTTPS reverse proxy for API + optional panel + MTA-STS policy host |
| **Fail2ban / nftables** | Brute-force jails and host firewall helpers |

## Main mail flow

1. External SMTP arrives at Postfix.
2. Rspamd milter scores SPF/DKIM/DMARC/ARC/spam (default action on milter failure: **tempfail**).
3. Accepted mail is delivered via LMTP to Dovecot.
4. Dovecot stores Maildir and enforces `quota_mb`.
5. Authenticated submission applies sender-login mismatch rejection and optional **per-mailbox send limits**.
6. External redirects may rewrite envelope sender through PostSRSd.

## Control plane

- Local bind default `127.0.0.1:8080`, published via Nginx on 443.
- Auth: HTTP Basic **or** Bearer after `/auth` MFA challenge.
- Privileged operations run through passwordless sudo helpers (`manage-*.sh`) with a narrow sudoers allow-list.
- Optional web panel (`/panel`) with Redis sessions + CSRF.

## Data model (MariaDB)

Core:

- `domains` — including DKIM dual-selector overlap, DNS provider metadata (tokens encrypted)
- `accounts` — quota, per-mailbox send rates, `require_app_password`, `mfa_hint`, optional `home_server_id`
- `aliases`, `redirects`
- `reputations`, `greylist`, `spam_traps`, `trusted_replies`, `blocklists_cache`

MFA & mail clients:

- `mfa_admin` — singleton admin TOTP/SMS settings
- `mfa_sms_providers` — Crisaleo / SMS2SMS credentials
- `mailbox_app_passwords` — argon2id app passwords for SMTP/IMAP/POP

Multi-node:

- `cluster_servers`, `cluster_sync_queue`
- optional `reputation_checks` history

Privacy-safe stats:

- `mail_traffic_events` — direction, mailbox, size, time only
- `mail_stats_state` — journal cursor

The SQLAlchemy ORM matches `database/schema.sql`. Schema changes are applied by the installer/update path.

## Identity model

| Actor | Mechanism |
|-------|-----------|
| Panel admin | Password → optional TOTP and/or SMS OTP → Redis session |
| API admin | Password → optional MFA → Bearer token (Basic alone blocked if MFA on) |
| Mailbox user (mail protocols) | Primary password and/or **app passwords**; no interactive OTP mid-IMAP/SMTP |

SMS OTP is delivered via configurable providers (Crisaleo SMS, SMS2SMS) using Crilide-style API keys.

## Topology modes

See `docs/TOPOLOGY.md`.

| Mode | Summary |
|------|---------|
| **standalone** | Single node (default) |
| **routed** | Split-domain mesh: mailboxes have a home server; shared or synced DB |
| **cluster** | Shared storage (NFS / Ceph / S3 + cache) behind multiple frontends |

Internode HTTPS + HMAC token for peer sync.

## Security posture

- Service user `limristem-mail` under hardened systemd (`ProtectSystem=strict`, etc.).
- API DB user: DML only; Postfix/Dovecot: **read-only** SQL user.
- Redis/MariaDB typically localhost + password.
- DKIM keys under `LIMRISTEM_MAIL_DKIM_KEYS_DIR` with shared `mailkeys` group for Rspamd.
- Fernet encryption for DNS/topology/SMS secrets (`config/.dns-token-key`).
- TLS 1.0/1.1 disabled for SMTP; message size default 50 MiB.
- Rate limits: Postfix client rates, global + per-mailbox send quotas, API auth lockout.

## Package distribution

| Channel | Host path (publish) | Public `version.json` |
|---------|---------------------|------------------------|
| **stable** | `get.limristem.eu/public/mail/` | `https://get.limristem.eu/mail/version.json` |
| **nightly** | `nightly.limristem.eu/public/mail/` | `https://nightly.limristem.eu/mail/version.json` |

Nightly keeps only `version.json` under `mail/`; archives and unpacked trees live in `mail/<version>/`.  
Nodes select the feed with `LIMRISTEM_MAIL_UPDATE_CHANNEL` / panel / `PATCH /admin/settings`.

## Operational tooling

- Backup/restore timers and panel-driven schedules/storages (rclone)
- Deliverability check/report + live DNS bundle export
- Mail stats collector timer
- DKIM auto-rotate timer
- Cluster sync timer (routed/synced)
- PostSRSd domain sync timer
- Performance report CLI

## Remaining external dependencies

- Public DNS and reverse DNS
- Public certificate trust
- IP reputation of the outbound host
- End-to-end SMTP/IMAP tests from the target network
