Skip to content

planetaryescape/mailbox-formats

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mailbox-formats

Crates.io Documentation License

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.

Install

[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"[..]));

Why this crate exists

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.

What it does

  • mbox reader — streaming BufRead-based iterator. Large mbox files can be read without loading the whole mailbox into memory.
  • mbox writer — append-mode Write wrapper.
  • All four mbox variants: Mboxo (no escape), Mboxrd (>From escape), Mboxcl and Mboxcl2 (Content-Length framed).
  • MboxVariant::Auto — sniffs the first few messages for Content-Length: headers and >From escaping signals.
  • Maildir reader — iterate cur/ and new/, 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-default FcntlThenDotlock.

What it does not do

  • No MIME parsing or header decoding. Headers stay as Vec<(String, Vec<u8>)> and the body as Vec<u8>. Pair with mail-parser or mailparse if you want decoded values.
  • No MH format. This crate focuses on mbox variants and basic Maildir.
  • No Maildir++ subfolders (.foo.bar/). Basic Maildir only.

Spec anchors

mbox variant guide

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.

Locking guide

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.

Forward compatibility

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.

Feature flags

  • serde — adds Serialize/Deserialize derives to all public types.

Verification

Run the package tests before relying on format or locking behavior:

cargo test --all-features

The test suite covers mbox variant parsing/writing, Maildir flag parsing and delivery, locking behavior, and mbox round-trips through the public API.

Out of Scope

These are intentionally outside this crate's current surface:

  • Maildir++ subfolder support (.foo.bar/ paths).
  • Dovecot keyword extension support (keep a-z flag characters in a keywords: Vec<String> field).
  • A mailbox-cli binary for converting between formats (mbox ↔ Maildir).
  • WASM or npm packaging.

Request one with concrete sample mailboxes or an integration use case.

Maintenance

License

MIT OR Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.

About

Read and write classic local-mail storage formats: mbox (mboxo/rd/cl/cl2) and Maildir.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages