Read and write classic local-mail storage formats: mbox (all four variants — mboxo, mboxrd, mboxcl, mboxcl2) and Maildir (basic, with atomic tmp→new delivery). Streaming reader, byte-preserving message representation, configurable concurrent-access locking.
[dependencies]
mailbox-formats = "0.1"use std::io::Cursor;
use mailbox_formats::{MboxReader, MboxVariant};
let bytes = b"From alice@example.com Mon Mar 17 09:36:40 2025\r\n\
From: Alice <alice@example.com>\r\n\
Subject: Hello\r\n\r\n\
Hi there.\r\n\r\n";
let mut reader = MboxReader::new(Cursor::new(&bytes[..]), MboxVariant::Mboxrd);
let msg = reader
.next()
.expect("one message")
.expect("message reads");
assert_eq!(msg.header("Subject"), Some(&b"Hello"[..]));Local mailbox formats sit between raw message parsing and full mail clients. Importers, backup tools, local-first mail apps, and migration jobs often need to preserve bytes while still handling mailbox-level details correctly.
mailbox-formats keeps that layer explicit: read and write mbox
variants plus basic Maildir, stream large inputs, and choose the locking
strategy at the call site. MIME parsing, header decoding, and provider
policy stay above this crate.
- mbox reader — streaming
BufRead-based iterator. Large mbox files can be read without loading the whole mailbox into memory. - mbox writer — append-mode
Writewrapper. - All four mbox variants:
Mboxo(no escape),Mboxrd(>Fromescape),MboxclandMboxcl2(Content-Length framed). MboxVariant::Auto— sniffs the first few messages forContent-Length:headers and>Fromescaping signals.- Maildir reader — iterate
cur/andnew/, parse flag suffix (:2,SRF). - Maildir writer — atomic
tmp/→new/delivery with DJB-style unique filenames (<seconds>.M<micros>P<pid>Q<counter>.<hostname>). - Concurrent-access locking — five strategies covering the common
mbox lock conventions:
None,Dotlock,Flock,Fcntl, and the Debian-defaultFcntlThenDotlock.
- No MIME parsing or header decoding. Headers stay as
Vec<(String, Vec<u8>)>and the body asVec<u8>. Pair withmail-parserormailparseif you want decoded values. - No MH format. This crate focuses on mbox variants and basic Maildir.
- No Maildir++ subfolders (
.foo.bar/). Basic Maildir only.
- mbox: RFC 4155 (Eric Allman's documentation of the format). Variants come from the original sendmail/Berkeley mail tradition and are documented at Wikipedia.
- Maildir: D. J. Bernstein's spec. Flag suffix and Maildir++ extensions documented at Courier.
- mbox locking conventions follow Dovecot's documentation.
| Variant | When to use | Escape rule |
|---|---|---|
Mboxrd |
Default for writing and interchange. | >*From body lines get an extra >. |
Mboxo |
Reading legacy files. Don't write new files in this. | None. From in body is heuristically guessed. |
Mboxcl |
Interoperating with old Unix utilities that use it. | None. Content-Length: header frames bodies. |
Mboxcl2 |
Rare; like Cl but never escapes. |
Same as Cl. |
Auto |
Reading a file of unknown provenance. | Sniffs the first ~64 KiB. |
When writing, Auto falls back to Mboxrd. When reading, Auto returns
UndetectedMboxVariant only if the stream is empty.
| Strategy | Where it works | When to use |
|---|---|---|
None (default) |
Everywhere | Read-only iteration; caller takes responsibility. |
Dotlock |
Unix + Windows | Interoperate with mutt/procmail's <path>.lock. |
Flock |
Unix + Windows | Single-host coordination only (advisory). |
Fcntl |
Unix only | NFS-aware POSIX record locking. |
FcntlThenDotlock |
Unix (Win: dotlock) | Try fcntl, then hold a dotlock fallback. |
On Windows, Fcntl is a no-op (POSIX advisory record locks don't
exist), and FcntlThenDotlock collapses to Dotlock alone. Flock
maps to LockFileEx.
[Lock] is an RAII guard — drop releases. Call Lock::release if you
want to handle release-time errors explicitly.
Every public enum is #[non_exhaustive]. Adding new variants (a new
mbox dialect, a new lock strategy) will be non-breaking. Pattern-
matching callers must include a _ => … arm.
serde— addsSerialize/Deserializederives to all public types.
Run the package tests before relying on format or locking behavior:
cargo test --all-featuresThe test suite covers mbox variant parsing/writing, Maildir flag parsing and delivery, locking behavior, and mbox round-trips through the public API.
These are intentionally outside this crate's current surface:
- Maildir++ subfolder support (
.foo.bar/paths). - Dovecot keyword extension support (keep
a-zflag characters in akeywords: Vec<String>field). - A
mailbox-clibinary for converting between formats (mbox ↔ Maildir). - WASM or npm packaging.
Request one with concrete sample mailboxes or an integration use case.
- File bug reports at https://github.com/planetaryescape/mailbox-formats/issues.
- Patches that change behaviour should ship with a test case (unit tests for parsing logic, integration tests for filesystem ops).
MIT OR Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.