Utilities for Maildir archive migration, indexing, and integrity verification.
These tools were written to migrate a 26-year, 2.34-million-message mail archive out of a set of monolithic mbox files and into per-month Maildir folders with trustworthy timestamps. They are deliberately conservative: the destructive operations are opt-in, reversible, and produce a manifest that can be verified independently after the fact.
| Tool | Purpose |
|---|---|
split-maildir.rc |
procmail recipe that files each message into a per-month Maildir |
mail-yyyy-mm |
filter that reduces a Date: header to YYYYMM |
maildir-retimestamp |
rewrites message timestamps from the Date: header, with manifest, verification, and rollback |
- Perl 5 with
Date::Parse,Digest::SHA, and the coreFile::*andPOSIXmodules procmailandformail, forsplit-maildir.rc- Sufficient free space on the destination volume for the expanded archive
mail-yyyy-mm must be in PATH for split-maildir.rc to find it.
split-maildir.rc delivers each message into $MAILROOT/YYYYMM/, creating
the cur, new, and tmp directories on demand. Messages whose date cannot
be determined are delivered to $MAILROOT/undated/ rather than being dropped.
Edit MAILROOT at the top of the recipe, then:
formail -s procmail split-maildir.rc < archive.mboxThe month is derived by piping the Date: header through mail-yyyy-mm.
That script takes the first logical Date: header, preserves folded
continuation lines, and ignores any subsequent duplicate Date: headers,
which are common in archives that have passed through multiple mail systems
over a long period. A header that cannot be parsed yields undated.
Splitting is I/O bound. On large archives it is worth running the operation against fast local storage even if the result is later moved elsewhere.
After a migration, filesystem timestamps generally reflect when the messages
were written to disk rather than when they were sent. maildir-retimestamp
corrects this from the Date: header.
The workflow is four stages, and only the second one changes anything.
# 1. Preview. Scans, writes a manifest, changes nothing.
maildir-retimestamp 201503
# 2. Apply the previewed changes.
maildir-retimestamp 201503 --apply MANIFEST
# 3. Confirm the result matches the manifest.
maildir-retimestamp 201503 --verify MANIFEST
# 4. Undo, if needed.
maildir-retimestamp 201503 --rollback MANIFESTOptions:
--root DIR archive root (default: $HOME/Mail)
--manifest-dir DIR manifest output (default: $HOME/MailRenameManifests)
The manifest is a tab-separated file carrying a format version, the source and target paths, the parsed epoch, and a SHA-1 of each message. Verification and rollback both read it, so it should be retained for as long as the operation might need to be audited or undone.
- Preview is the default. Running the tool with no mode flag never modifies a message or a timestamp.
- Messages are moved without overwriting. An existing target is treated as a conflict rather than silently replaced.
- Message content is hashed before and after, so verification detects corruption as well as misplacement.
- The tool refuses to run while a mail process is active, to avoid racing a delivery agent over the same directory.
- Destructive stages prompt for confirmation.
- Rollback restores the original names and timestamps from the manifest.
- A message with no
Date:header, an unparseable one, or a date preceding the Unix epoch is reported and skipped rather than guessed at. Date:headers are trusted as written. A message with a wrong or forged date will be filed and timestamped according to that date.- Month boundaries follow the local timezone of the machine running the tools, so a message sent near midnight UTC may file into an adjacent month relative to a run on a differently configured host.
split-maildir.rccontains a hardcodedMAILROOTand aPATHreflecting the author's environment. Both need editing before use.- Only
curandneware processed.tmpis ignored by design.
BSD 2-Clause. See LICENSE.