# lightmails for agents and CLI setup

lightmails (https://lightmails.com) is a privacy-first mail gateway written in Rust. One static Linux binary, `lightmail`, is both the server and the self-hosted node. The website is German; this file is the machine-oriented reference. Canonical URL: https://lightmails.com/llm.md

## Model in five lines
- MX of a customer domain points to `mail.lightmails.com` (the gate). It accepts mail, immediately seals each message to the target mailbox's public key (X25519 sealed box, ChaCha20-Poly1305) and keeps only the sealed blob.
- **Hybrid** (recommended): a `lightmail node` on the customer's own Linux server pulls sealed mail over outbound HTTPS every 30 s, decrypts locally with a private key that never leaves the node, stores it in local SQLite and serves IMAP/SMTP submission locally. After the node acknowledges, the gate hard-deletes its copy (hard cap 30 days if the node is offline).
- **Hosted**: mailboxes live at lightmails (100 MB per workspace by default, raisable by the operator). Messages stay sealed; IMAP/webmail unlock the key with the mailbox password.
- Outgoing mail is DKIM-signed (RSA-2048, selector `lm1`) and delivered by the gate; nodes send through `POST /api/node/v1/send`.
- Workspaces hold domains, mailboxes, nodes and members (roles owner, admin, member; per-domain grants domain_admin, mailbox_user).

## Quick start: connect a node (non-interactive)
Prerequisites: Linux x86_64 with systemd, root, outbound HTTPS to lightmails.com. (aarch64 is not available yet.)

1. In the panel (https://lightmails.com/app/) create a workspace, add a domain in mode `hybrid`, then Nodes → "Node hinzufügen". The panel shows a one-time enrollment token (valid 24 h).
2. On the server:
```sh
curl -fsSL https://lightmails.com/install.sh | sudo LIGHTMAIL_TOKEN=<token> sh
```
The script downloads `/download/lightmail-linux-x86_64`, verifies the SHA-256 from `/download/lightmail-linux-x86_64.sha256`, creates the system user `lightmail`, installs `/usr/local/bin/lightmail` and the unit `lightmail-node.service`, enrolls the node and starts it. Read it first: https://lightmails.com/install.sh
3. Create mailboxes (either in the panel, then the node generates the key itself on the next sync, or on the node):
```sh
sudo -u lightmail lightmail node mailbox create anna@example.com            # prints a generated password once
sudo -u lightmail lightmail node mailbox create anna@example.com --password 'long-password-here'
echo 'new-long-password' | sudo -u lightmail lightmail node mailbox passwd anna@example.com   # min. 10 chars, read from stdin
sudo -u lightmail lightmail node mailbox list
sudo -u lightmail lightmail node mailbox delete anna@example.com
sudo -u lightmail lightmail node status
journalctl -u lightmail-node -f
```
4. Mail client: user = full address, password as set. IMAP `SSL/TLS` port 993 (also STARTTLS on 127.0.0.1:1143), SMTP submission port 587 with STARTTLS and AUTH. The node generates a self-signed certificate on first start; place your own at `/var/lib/lightmail-node/tls/cert.pem` and `key.pem` and restart the service.

Without the installer (manual): `lightmail node --data /var/lib/lightmail-node enroll <token> --server https://lightmails.com` then `lightmail node --data /var/lib/lightmail-node run`.

Node files in `/var/lib/lightmail-node`: `config.json` (server, node_key, ports, poll_secs), `node.db` (mailboxes with private keys, messages), `status.json`, `tls/`. Back this directory up. Lost private keys mean sealed mail cannot be opened; nobody else holds them.

`config.json` fields: `server`, `node_key`, `node_id`, `imap_plain` (default `127.0.0.1:1143`), `imaps` (`0.0.0.0:993`), `submission` (`0.0.0.0:587`), `poll_secs` (30).

## DNS for a domain
The panel shows the exact values and can set them via Cloudflare (API token with Zone:Read and DNS:Edit, stored AES-256-GCM encrypted). Required records for `example.com`:
| Type | Name | Value |
|---|---|---|
| MX | example.com | `mail.lightmails.com` priority 10 |
| TXT | example.com | `v=spf1 include:_spf.lightmails.com ~all` |
| TXT | lm1._domainkey.example.com | `v=DKIM1; k=rsa; p=<public key from panel>` |
| TXT | _dmarc.example.com | `v=DMARC1; p=quarantine; adkim=r; aspf=r` |
The domain becomes `active` when MX, SPF and DKIM resolve (checked every 30 s for 15 min, or press "Jetzt prüfen").

## Panel HTTP API (JSON, base `/api/v1`)
Session cookie `lm_session` (HttpOnly) plus header `X-CSRF-Token` on every non-GET (value from `POST /auth/login` or `GET /me`). Errors: `{"error": code, "message": text}`.
- Auth: `POST /auth/register {email,name?,accept_terms:true}` (mail with link; the password is set at `POST /auth/verify {token,password}`), `/auth/resend`, `/auth/login {email,password}` (may return `mfa_required`), `/auth/logout`, `/auth/forgot`, `/auth/reset {token,password}`, `/auth/change-password`, `GET /me`, `GET /config`.
- Passkeys: `/auth/passkeys/register/begin|finish`, `/auth/passkey/auth/begin|finish`, `DELETE /auth/passkeys/{id}`, `POST /auth/recovery-codes`, `/auth/login-recovery`. GitHub: `GET /auth/github/start` (only if configured).
- Workspaces: `GET|POST /workspaces`, `GET|PATCH|DELETE /workspaces/{id}`, `/workspaces/{id}/members`, `/invites`, `/audit`, `/nodes`, `/domains`.
- Domains: `GET|PATCH|DELETE /domains/{id}`, `POST /domains/{id}/check`, `POST /domains/{id}/cf/connect {token}`, `POST /domains/{id}/cf/setup`, `DELETE /domains/{id}/cf`, `/domains/{id}/mailboxes`, `/aliases`, `/grants`.
- Mailboxes: `DELETE /mailboxes/{id}`, `PUT /mailboxes/{id}/password`, hosted webmail `POST /mailboxes/{id}/inbox {password}`, `/messages/{mid}`, `/messages/{mid}/delete`.
- Operator (superadmin only): `/admin/stats|accounts|workspaces|audit`.
Creating a hosted mailbox requires `password` (min. 10 chars); hybrid mailboxes are created without a key and get it from the node.

## Node API (`/api/node/v1`, header `X-Node-Key`)
`POST /enroll {token,version}` → `{node_id,node_key}` (token single use), `POST /sync {keys:[{address,public_key_b64}],version}` → mailbox list, `POST /poll` → up to 50 sealed messages `{id,address,sealed_b64,received_at}`, `POST /ack {ids}` (hard delete), `POST /send` (raw MIME body, headers `X-Mail-From`, `X-Rcpt` comma separated; sender domain must belong to the node), `POST /mailboxes {address,public_key_b64}`, `POST /mailboxes/delete {address}`. Rate limit 120 requests/min per key. Sealed format: `[0x01][32 B ephemeral X25519 public][12 B nonce][ciphertext+tag]`, key = HKDF-SHA256(salt = eph_pub || rcpt_pub, ikm = X25519 shared secret, info = `lightmail-seal-v1`), AAD = `[0x01]`.

## Run your own lightmails server (operator)
Build (Rust stable, musl for a static binary): `cargo build --release --target x86_64-unknown-linux-musl`. Needs ports 25, 80, 143, 443, 587, 993, a public IPv4 with matching reverse DNS (`mail.<your-domain>`), outbound port 25.
Configuration via environment (file `/etc/lightmail/lightmail.env`, mode 0600), all also available as flags of `lightmail serve`:
`LIGHTMAIL_DATA` (default `/var/lib/lightmail`), `LIGHTMAIL_BASE_URL`, `LIGHTMAIL_MAIL_HOST`, `LIGHTMAIL_PUBLIC_IPV4`, `LIGHTMAIL_PUBLIC_IPV6`, `LIGHTMAIL_SUPERADMIN_EMAIL` (that address becomes superadmin when it registers), `LIGHTMAIL_ACME_EMAIL`, `LIGHTMAIL_CF_TOKEN` (own zone: sets A/MX/SPF/DKIM/DMARC records at first start), `LIGHTMAIL_GITHUB_CLIENT_ID` / `LIGHTMAIL_GITHUB_CLIENT_SECRET` (callback `<base>/api/v1/auth/github/callback`), `LIGHTMAIL_NO_TLS`, `LIGHTMAIL_NO_ACME`, `LIGHTMAIL_ACME_STAGING`, `LIGHTMAIL_SECRET_KEY_FILE` or `LIGHTMAIL_MASTER_KEY` (hex, 32 bytes; generated at `<data>/secret.key` on first start; back it up separately from the database).
Certificates: Let's Encrypt via HTTP-01 for the base host and the mail host, renewed automatically.
Operator CLI (run as the service user with the env loaded):
```sh
lightmail admin --data /var/lib/lightmail create-account ops@example.com --superadmin   # password from stdin
lightmail admin --data /var/lib/lightmail grant-superadmin ops@example.com
lightmail admin --data /var/lib/lightmail send-test someone@example.org
lightmail admin --data /var/lib/lightmail dkim-sample example.com   # signed sample message, verify against live DNS
```
Data: SQLite (WAL) at `<data>/lightmail.db`. Secrets in the database (Cloudflare tokens, passkeys, DKIM keys) are AES-256-GCM encrypted with the master key; messages are sealed per mailbox.

## Limits and honest caveats
- During SMTP reception and sending a message is briefly in server memory as plaintext. Envelope data (recipient, size, time) is kept until the node acknowledges. Logs contain no addresses, IPs or content.
- Hosted mailbox keys are held in memory for the duration of an IMAP session (up to 30 min idle) or per webmail request.
- Not implemented yet: rules/auto-reply/blocklist, PostgreSQL backend, aarch64 build. New domains and IPs have no reputation; mail to large providers may land in spam until it builds up.
- Defaults: 25 MB message limit, 50 recipients, 512 MB relay buffer per workspace, 100 MB hosted quota per workspace, max 3 domains / 25 mailboxes / 10 members per workspace (operator-adjustable).

Legal: https://lightmails.com/impressum/ · https://lightmails.com/datenschutz/ · https://lightmails.com/avv/ · https://lightmails.com/sicherheit/
