eml_parser/
eml.rs

1use std::fmt;
2
3#[derive(Debug)]
4pub struct HeaderField {
5    pub name: String,
6    pub value: HeaderFieldValue,
7}
8
9#[derive(Debug, std::cmp::PartialEq)]
10pub enum EmailAddress {
11    AddressOnly { address: String },
12    NameAndEmailAddress { name: String, address: String },
13}
14
15#[derive(Debug, std::cmp::PartialEq)]
16pub enum HeaderFieldValue {
17    SingleEmailAddress(EmailAddress),
18    MultipleEmailAddresses(Vec<EmailAddress>),
19    Unstructured(String),
20    Empty,
21}
22
23#[derive(Debug, Default)]
24pub struct Eml {
25    pub headers: Vec<HeaderField>,
26    pub from: Option<HeaderFieldValue>,
27    pub to: Option<HeaderFieldValue>,
28    pub subject: Option<String>,
29    pub body: Option<String>,
30}
31
32impl fmt::Display for EmailAddress {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        match self {
35            EmailAddress::AddressOnly { address } => write!(f, "{address}"),
36            EmailAddress::NameAndEmailAddress { name, address } => {
37                write!(f, r#""{name}" <{address}>"#)
38            }
39        }
40    }
41}
42
43/// Custom formatting for header values.
44/// For example, an email may comprise a name and address formatted as: "Name" <email>
45impl fmt::Display for HeaderFieldValue {
46    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47        match self {
48            HeaderFieldValue::SingleEmailAddress(address) => write!(f, "{address}"),
49            HeaderFieldValue::MultipleEmailAddresses(addresses) => {
50                // A probably acceptable heurestic for pre-allocating some memory
51                let mut combined = String::with_capacity(20 * addresses.len());
52                addresses.iter().enumerate().for_each(|(i, a)| {
53                    if i > 0 {
54                        combined.push_str(", ");
55                    }
56                    combined.push_str(&a.to_string());
57                });
58                write!(f, "{combined}")
59            }
60            HeaderFieldValue::Unstructured(s) => write!(f, "{s}"),
61            HeaderFieldValue::Empty => write!(f, ""),
62        }
63    }
64}