We’ve been steadily moving apps that used to live inside PIM core — diary, task, worklog, calendar, and the rest — out into their own standalone modules, loaded into PIM at runtime instead of compiled into it. Mail was next, and it broke the pattern.

Every earlier extraction had exactly one consumer: the interactive PIM app, which loads these modules dynamically at startup. Mail has two. Historical Backfill — scanning years of mail history — runs in mail-worker, a separate daemon process PIM spawns so a large mailbox never slows down the interactive app. mail-worker depended on Mail’s code at compile time, so simply moving that code out from under it would have broken the build — and PIM’s build must never depend back on an extracted module.

The fix was to teach mail-worker to load modules dynamically too, the same way the interactive app already does, instead of compiling Mail’s classes in directly. That also meant swapping one other direct dependency: the part of PIM that spawns mail-worker needs to know which mail accounts are configured, and it can’t know at compile time which module will actually be providing that information. A small interface took the place of the concrete class.

With Mail’s code out, the sharper question became what belongs in the core Mail app versus what’s specific to one way of getting mail. Mail today only reads a local mbox/eml store, but it won’t always — live IMAP or a provider API are reasonable additions later, the same relationship our IM support already has between one shared connector contract and its Telegram/Matrix implementations. We used that as the template for where to draw the line, before a second Mail source actually exists: event routing, thread-grouping, the hand-off-only send policy, and the account/review state machine are all source-agnostic and stay in the core app; only the actual fetching is implementation-specific and belongs in a per-source module. A couple of seams — how the reader looks up the “next” and “previous” message, and how an account is described — still quietly assume a local file today. Generalizing those is the concrete work still ahead of adding a second source.