Skip to main content

eml_codec/
lib.rs

1#![doc = include_str!("../README.md")]
2
3/// Parse and represent full "top-level" emails (RFC 822, RFC 2045, RFC 2046)
4pub mod message;
5
6/// Parse and represent emails "parts" as defined by MIME (RFC 2046)
7pub mod part;
8
9/// Parse and represent IMF (Internet Message Format) headers (RFC 822, RFC 5322)
10pub mod imf;
11
12/// Parse and represent MIME headers (RFC 2045, RFC 2047)
13pub mod mime;
14
15/// MIME and IMF represent headers the same way: module contains their common logic
16pub mod header;
17
18/// Low-level email-specific text-based representation for data
19pub mod text;
20
21/// Printing with email-specific line folding
22pub mod print;
23
24/// Helpers related to UTF-8 support in headers (RFC 6532)
25pub mod i18n;
26
27/// Support for storing references to raw input slices in AST nodes.
28pub mod raw_input;
29
30/// Custom equality trait used for fuzz-checking
31#[cfg(feature = "arbitrary")]
32pub mod fuzz_eq;
33
34mod utils;
35
36#[cfg(feature = "arbitrary")]
37mod arbitrary_utils;
38
39// Re-export bounded_static because we implement its traits
40pub use bounded_static;
41
42/// Parse a whole email including its (MIME) body
43///
44/// # Arguments
45///
46/// * `input` - A buffer of bytes containing your full email
47///
48/// # Returns
49///
50/// * `msg` - The parsed message
51///
52/// # Examples
53///
54/// ```
55/// let input = br#"Date: 7 Mar 2023 08:00:00 +0200
56/// From: deuxfleurs@example.com
57/// To: someone_else@example.com
58/// Subject: An RFC 822 formatted message
59/// MIME-Version: 1.0
60/// Content-Type: text/plain; charset=us-ascii
61///
62/// This is the plain text body of the message. Note the blank line
63/// between the header information and the body of the message."#;
64///
65/// let email = eml_codec::parse_message(input);
66/// println!(
67///     "{} message structure is:\n{:#?}",
68///     email.imf.from_or_sender().unwrap().to_string(),
69///     email,
70/// );
71/// ```
72pub fn parse_message(input: &[u8]) -> message::Message<'_> {
73    message::message(input)
74}
75
76/// Print a whole email.
77///
78/// The `seed` parameter controls the RNG used to generate multipart boundaries.
79/// Passing `None` will use randomness from the operating system.
80pub fn print_message(msg: message::Message<'_>, seed: Option<u64>) -> Vec<u8> {
81    print::print_to_vec(print::FMT_DEFAULT.with_seed(seed), msg)
82}
83
84/// Only extract the headers of the email that are part of the Internet Message Format spec
85///
86/// Emails headers contain MIME and IMF (Internet Message Format) headers.
87/// Sometimes you only need to know the recipient or the sender of an email,
88/// and are not interested in its content. In this case, you only need to parse the IMF
89/// fields and can ignore the MIME headers + the body. This is what this function does.
90///
91/// # Arguments
92///
93/// * `input` - A buffer of bytes containing either only the headers of your email or your full
94///   email (in both cases, the body will be ignored)
95///
96/// # Returns
97///
98/// * `rest` - The rest of the buffer, ie. the body of your email as raw bytes
99/// * `imf` - The parsed IMF headers of your email
100///
101/// # Examples
102///
103/// ```
104/// let input = br#"Date: 7 Mar 2023 08:00:00 +0200
105/// From: deuxfleurs@example.com
106/// To: someone_else@example.com
107/// Subject: An RFC 822 formatted message
108/// MIME-Version: 1.0
109/// Content-Type: text/plain; charset=us-ascii
110///
111/// This is the plain text body of the message. Note the blank line
112/// between the header information and the body of the message."#;
113///
114/// let (_, imf) = eml_codec::parse_imf(input);
115/// println!(
116///     "{} just sent you an email with subject \"{}\"",
117///     imf.from_or_sender().unwrap().to_string(),
118///     imf.subject.unwrap().to_string(),
119/// );
120/// ```
121pub fn parse_imf(input: &[u8]) -> (&[u8], imf::Imf<'_>) {
122    message::imf(input)
123}
124
125/// Get the raw subslice of the input that corresponds to the header section.
126///
127/// It can be later parsed using `parse_imf` or `parse_message` (resulting in an
128/// empty body). This is equivalent to directly parsing the full input, but
129/// allows the header section to e.g. be stored separately without storing the
130/// body.
131pub fn raw_headers(input: &[u8]) -> &[u8] {
132    let (rest, _) = header::header_kv(input);
133    &input[0..input.len() - rest.len()]
134}