Chapter 16 / 40
Status: Blocked — waiting for the Framework Desktop and for Jack’s ISP ticket to return a static IPv4 address with port 25 access. The ISP ticket is the only path.
All 33 Sodimo mailboxes run on the Framework Desktop in the Gennevilliers server room. Postfix delivers mail, Dovecot stores it, rspamd filters and signs it, Piler archives it. Each service is a Podman quadlet on the Fedora harness (Chapter 35), so a power cut or a reboot brings mail back up with nothing for anyone to do.
Today: 33 mailboxes across four domains at Strato. Strato gives no control over the archive, no deletion guarantees, and no sovereignty over Sodimo’s correspondence.
Target: Self-hosted mail on the Fedora harness. Every message — inbound and outbound — lives on hardware Sodimo controls. No hosting cost. No external archive provider.
What the team needs to do:
- Jack: escalate the ISP ticket — static IPv4 address and port 25 access. This is the single most important action before mail migration can start.
- Paul: approve the mailbox skip list (a small set of legacy service accounts that will not be migrated). The CNIL employee transparency notice is deferred to the Chapter 6 handover; the whole team reads it once at that point.
- Everyone else: nothing during migration. Mail continues to flow normally on Strato while each domain flips in the background.
Migration order (test domains first, sodimo.eu last):
yallafood.eu → cavisteduliban.fr → sodimonet.fr → sodimo.eu
sodimo.eu moves last because it carries the most weight. Strato stays live for four weeks after each flip as a fallback — extra safety for the delta imapsync that catches any messages still arriving on the old server. If anything goes wrong, the MX records revert in minutes.
DMARC ramp. Each domain starts at p=none while DKIM signatures are validated at Gmail and Outlook. Once the signatures are clean at both providers, the domain moves straight to p=reject. The quarantine step is skipped — it adds delay without adding information.
Retention: hold all emails, forever.
Every email — inbound and outbound — is retained indefinitely, with a working cap of approximately 100 GB on the archive. Nothing is aged out. Nothing is deleted on a schedule. If a message was ever delivered to or sent from a Sodimo mailbox, it is in Piler.
Piler is the archive: a write-once, full-text-searchable index that sits behind Postfix and Dovecot. When the 100 GB cap is approached, the operator provisions more storage — Piler is not a rotating buffer.
- People search the archive through Piler’s admin UI, reached over Tailscale (Chapter 31) — no account per person, no per-inbox permission model.
- Claude searches the archive through a service token on the MCP server (Chapter 42). The token is how AI tools find threads and attachments for a customer without needing per-person credentials.
The accountant confirms the minimum retention the French commercial and tax codes require. Indefinite covers it.
Shared inboxes. info@, contact@, business@, exports@, commandes@ work as shared folders in each participant’s mail client. Existing sodimo.eu aliases are preserved exactly — MCP tools speak English internally (orders@ is the English alias of commandes@), but the email addresses customers know don’t change. The team adds and removes aliases directly.
Sending mail from the AI layer
Every email the AI stack sends — a collection-letter draft Paul approved, an order acknowledgment, a follow-up, anything — goes through the same round-trip. The AI does not touch Postfix directly; it calls an MCP tool on the Cloudflare Worker, and a small service on the Fedora harness pulls the message from a queue and hands it to sendmail. This is a deliberate application of Principle 3 (Chapter 15): one sender-authorization policy, one unified run ledger, one place to rate-limit.
The Fedora harness exposes no inbound port for this path. cloudflared is not involved. If the box is offline, messages queue for up to four days (Cloudflare Queue default retention) and drain when it returns. Failed sends retry with backoff up to three attempts, then land in email_dlq for manual inspection.
Why this shape, and not a direct call from the agent to sendmail. Four properties the round-trip preserves — each of which is permanently lost if any producer bypasses the Worker:
- Unified run ledger. Every email-send is a row in
run_ledger(Chapter 15, Principle 2). A shortcut to localsendmailproduces an invisible send and breaks the savings study. - Single sender-authorization policy. The Worker’s
ALLOWED_SENDERScheck is source-of-truth for who sends as whom. Two policies drift; one does not. - Uniform observability. One tool, one schema, one place. “Every email the AI stack sent this week” is one SQL query against
run_ledger. - Rate-limiting and dead-letter handling. A runaway agent loop hits a queue with backpressure and a DLQ, not Postfix at full speed — which is how IP reputation is lost for weeks.
Rollback. If DKIM fails at Gmail or Outlook after a flip, the MX records revert immediately. Each domain’s cutover has a named decision owner and a 15-minute decision window.