Skip to main content

Crate mailrs_rfc5322

Crate mailrs_rfc5322 

Source
Expand description

§mailrs-rfc5322

Crates.io docs.rs License

Pull-based RFC 5322 message parser. Lazy header lookup, byte-level scan, zero-allocation borrowed slices. Skip-ahead to the header you want without building the full Message tree.

The crate exists because building a full typed Message tree on every inbound SMTP receive is wasted work when the receiver only needs 1-5 specific headers (Subject, From, Message-ID, Authentication-Results, …). This parser scans for the header you ask for and stops; the rest of the message is never touched.

§Quickstart

use mailrs_rfc5322::Message;

let raw = b"\
From: alice@example.com\r\n\
To: bob@example.com\r\n\
Subject: hi\r\n\
\r\n\
Hello, world!\r\n";

let msg = Message::new(raw);
assert_eq!(msg.header_str("Subject"), Some("hi"));
assert_eq!(msg.header("From"), Some(b"alice@example.com" as &[u8]));
assert_eq!(msg.body(), Some(b"Hello, world!\r\n" as &[u8]));

// Multiple Received: chains
for received in msg.header_all("Received") {
    println!("hop: {:?}", received.value);
}

§When to reach for this vs. mail-parser

Use casePick
Read 1-5 specific headers per inbound messagemailrs-rfc5322
Decide if a message has a text/plain partmailrs-rfc5322 + downstream MIME
Display a full message tree with all MIME parts decoded, all RFC 2047 encoded-words resolved, all addresses parsed into structured (name, email) tuplesmail-parser
Verify SPF/DKIM/DMARC (reads message bytes + a few headers)mailrs-rfc5322

mailrs-rfc5322 is intentionally minimal. It does not decode RFC 2047 encoded-words, not parse MIME bodies into a tree, not extract (display-name, email) from address fields. It hands you the raw header value bytes and lets you decide what to do.

§What this crate does

  • Header lookup by name, case-insensitive (Message::header, Message::header_str, Message::header_all)
  • Iteration over all headers in document order (Message::headers)
  • Body access (Message::body) — bytes after the header terminator, memoized
  • RFC 5322 §3.2.2 line folding handled (continuation lines starting with whitespace are kept inside the same header value)
  • LF-only and CRLF line endings both accepted
  • Zero allocation. Every returned &[u8] / &str borrows from the input message bytes.
  • Zero dependencies. The crate compiles to a small object that pulls in nothing transitive.

§What this crate does not do (and won’t, in 1.x)

  • RFC 2047 encoded-word decoding (=?utf-8?B?...?= in header values). Use a downstream crate.
  • MIME body parsing (multipart/, Content-Transfer-Encoding). Use mail-parser or a focused MIME crate.
  • Address field structured parse (From: "Name" <addr@example>). Hand the value to a focused crate.
  • RFC 6532 UTF-8-in-headers validation. Bytes are returned raw; the _str helpers do a UTF-8 check but don’t do canonical comparison.

If a 1.x version “added MIME parsing” it would defeat the purpose. Future MIME work goes in a separate crate.

§Performance

Measured (criterion, M-series Mac, release, 100-sample median):

Operationbody sizemailrs-rfc5322mail-parser 0.11speedup
Subject + From lookup1 KB212 ns2383 ns11.2×
Subject + From lookup5 KB212 ns3378 ns15.9×
Subject + From lookup20 KB212 ns6901 ns32.5×
Target at end of 50 headers (worst case)393 nsn/an/a
body offset locate1 KB249 ns2387 ns9.6×
body offset locate5 KB247 ns3337 ns13.5×
body offset locate20 KB248 ns6855 ns27.6×
Received-chain walk (3 hops, 5 KB body)340 ns3382 ns9.9×

Note the mailrs-rfc5322 numbers are constant in body size — ~280 ns for header lookup regardless of whether the body is 1 KB or 20 KB. That’s because the scanner stops at the empty-line terminator separating headers from body. mail-parser builds the full Message tree on every parse, so it’s linear in body size.

Reproduce with cargo bench -p mailrs-rfc5322 --bench parse. Workspace PERFORMANCE.md carries the same table; per the project’s “no fake numbers” rule, every number traces to a measurement.

§License

Apache-2.0 OR MIT. Internal layout: a single Message<'a> borrows the message bytes. Header lookup is a forward scan of the header region; body access locates and caches the offset of the empty line that terminates the header section.

Structs§

Header
One header line in a message, returned by HeaderIter.
HeaderIter
Iterator over all headers in a message, in the order they appear.
Message
A parsed-on-demand RFC 5322 message backed by the caller’s bytes.