Affinity: the moderation queue, explained
Affinity rebuilds the Mailman 3 admin around the one screen list owners live in: the moderation queue.
Mailing lists are quiet infrastructure. Nobody notices them until a message does not arrive, an archive link 404s, or a migration drops half the subscribers. The difference between a list that runs for fifteen years and one that limps along is rarely the software version. It is the operational detail around it: how bounces are processed, how DNS is aligned, how archives are indexed, and how carefully a move from one system to another is rehearsed.
The part everyone underestimates
Every list move has a boring middle that determines whether it succeeds. It is not the export or the import; it is the reconciliation between them, where member states, moderation flags, and archive references have to line up exactly.
- Subscriber states: enabled, disabled by bounce, disabled by owner, and by-request must all survive.
- Per-list settings: reply-to munging, digest options, and moderation defaults.
- Archive continuity: old permalinks should resolve, not redirect to a search page.
- Header rewriting: DMARC-safe From handling that does not mangle display names.
When those four line up, the migration is invisible to subscribers. When one slips, you get a flood of “why am I getting welcome mail again” tickets within the hour.
Rehearse against a copy, never production
The single most effective practice is a full dry run against a clone of the real data. Synthetic test lists never reproduce the messy states real lists accumulate over a decade.
- Clone the production database and archive store to a staging host.
- Run the migration end to end and diff member counts per list.
- Spot-check archives for threading and attachment integrity.
- Only then schedule the real cutover, with the dry-run numbers as your baseline.
The dry run also gives you a rollback plan for free: you already know what the before and after look like, so you can prove nothing was lost.
Communicate the way subscribers expect
Owners care about two things: that their members are intact and that nobody gets spammed by the move. A short, specific note before the cutover prevents most support load.
- Tell owners the exact window and what will and will not change.
- Promise no welcome mail, then keep that promise in the tooling.
- Give one contact path for issues, staffed during the window.
- Publish the archive URL scheme so links in old emails keep working.
Good communication is not a courtesy here, it is a load-bearing part of the migration. It is the difference between ten questions and ten thousand.
A migration you can prove is reversible is a migration you can run on a Friday. One you cannot, you should not run at all.
A concrete example
Consider a university that runs 4,000 announce-only lists and 600 discussion lists. The announce lists are simple, but the discussion lists carry threading, per-topic moderation, and two decades of archives. A naive export drops the threading and re-sends welcome mail to everyone. A rehearsed migration preserves message IDs, keeps the archive URLs stable, and never touches the subscriber’s inbox.
# dry-run first, always
$ mailman-migrate --from mm2 --to mm3
--preserve-archives --preserve-message-ids
--no-welcome --dry-run
# 12,431 members, 0 conflicts, 18 archives linked
None of this is exotic. It is discipline applied to unglamorous detail, which is exactly what dependable list hosting is made of.