1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//! RFC 5322 / MIME parser producing a byte-range-indexed part tree.
//!
//! # Quick start
//!
//! ```rust
//! use mime_tree::{parse, decode_body_value};
//!
//! let raw = b"From: alice@example.com\r\n\
//! Content-Type: text/plain; charset=utf-8\r\n\
//! \r\n\
//! Hello, world!\r\n";
//!
//! let msg = parse(raw).expect("parse failed");
//!
//! // text_body / html_body / attachments follow RFC 8621 §4.1.4.
//! assert_eq!(msg.text_body, vec!["1"]);
//!
//! // Decode a body part on demand (transfer-decode + charset-convert).
//! let part = msg.part_index.find_by_id("1").unwrap();
//! let decoded = decode_body_value(raw, part, None).unwrap();
//! assert_eq!(decoded.value, "Hello, world!\r\n");
//! ```
//!
//! # Design
//!
//! - `parse()` returns a [`ParsedMessage`] with the MIME part tree and RFC 8621
//! `text_body` / `html_body` / `attachments` part-ID lists.
//! - Each [`ParsedPart`] carries `(offset, length)` byte ranges into the
//! original `&[u8]` — no raw bytes are stored internally.
//! - `decode_body_value()` decodes a part's body on demand: transfer-encoding
//! decode (Base64, QP, identity) followed by charset conversion via `encoding_rs`.
//! - Parsing is best-effort: malformed input yields a partial result plus
//! `ParsedMessage::warnings`. Only empty input or no-headers returns `Err`.
//! - No JMAP dependency. No async. No `unsafe`.
pub use ParseError;
pub use ;
pub use ;
pub use ;