# mm3-hk-export Export a private **HyperKitty** (Mailman 3) list archive to mbox from the command line — the CLI equivalent of the web UI's Download button. ## Why HyperKitty ships no `hyperkitty_export` command; the only built-in export is the web Download view. This drives the same `Email.as_bytes()` path through the `mailman-web` wrapper, so the output is byte-for-byte identical — no web login, no DB reconstruction. It has to be `mailman-web`, not `mailman-wrapper`: the archive lives in the HyperKitty DB, not core. ## Requirements Run as **root** — `mailman-web` drops to the web user to read the archive, then the script publishes the result as root. Uses `mailman-wrapper` to report a list's `archive_policy` when there's nothing to export. ## Usage ``` mm3-hk-export [-z|--gzip] [output] ``` `output` defaults to `./.mbox` (`.mbox.gz` with `-z`). `-z` gzips the stream to match the web `.mbox.gz` byte-for-byte (deterministic header, `mtime=0`). ```sh mm3-hk-export announce@lists.example.com /root/mm3/announce.mbox mm3-hk-export --gzip announce@lists.example.com /root/mm3/announce.mbox.gz ``` ## Exit codes Never writes a partial or empty file. The exit code reports whether a backup was produced: | Exit | Meaning | |:--:|---| | `0` | archive written (`wrote N messages to …`) | | `3` | nothing to archive — empty list, or no archive at all (reports `archive_policy`: `never` vs nothing-yet) | | `2` | usage / bad address | | `1` | error (e.g. `mailman-web` failed) | `3` is distinct from `0` so a caller can tell "backed up" from "nothing to back up" and refuse to destroy an uncaptured list. ## Gating a removal on the backup The script only exports. To remove a list after a verified backup, gate it on the exit code yourself: ```sh mm3-hk-export "$addr" "/root/mm3/$list.mbox" \ || { echo "no backup; keeping $addr" >&2; exit 1; } mailman-wrapper members "$addr" > "/root/mm3/$list.members" mailman-wrapper remove "$addr" ``` Export before `remove`, never `remove` on a non-zero exit. (Core's `remove` leaves the HyperKitty archive untouched anyway — separate DB — but a failed export must still halt the destroy.) ## Caveats - **Reconstruction, not the original bytes.** HyperKitty rebuilds each message from parsed fields (`From`, `To`, `Subject`, `Date`, `Message-ID`, `In-Reply-To`, body, attachments); `Cc`, `References`, `List-*`, and `X-*` are lost. Inherent to HyperKitty — the web download is identical. - **Large lists.** Streamed via a DB iterator, so no memory blow-up like the web export. - **Re-import.** Valid mbox; re-importable with `hyperkitty_import`. - **Handoff.** The web user builds the archive in `/var/tmp`; root verifies it by SHA-256 and publishes atomically, so a swap, truncation, or corruption before publish is caught and nothing is published. A compromised `mailman-web` is out of scope.