lettre/address/
envelope.rs

1use super::Address;
2#[cfg(feature = "builder")]
3use crate::message::header::{self, Headers};
4#[cfg(feature = "builder")]
5use crate::message::{Mailbox, Mailboxes};
6use crate::Error;
7
8/// Simple email envelope representation
9///
10/// We only accept mailboxes, and do not support source routes (as per RFC).
11#[derive(PartialEq, Eq, Clone, Debug)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Envelope {
14    /// The envelope recipient's addresses
15    ///
16    /// This can not be empty.
17    #[cfg_attr(
18        feature = "serde",
19        serde(deserialize_with = "serde_forward_path::deserialize")
20    )]
21    forward_path: Vec<Address>,
22    /// The envelope sender address
23    reverse_path: Option<Address>,
24}
25
26/// just like the default implementation to deserialize `Vec<Address>` but it
27/// forbids **de**serializing empty lists
28#[cfg(feature = "serde")]
29mod serde_forward_path {
30    use super::Address;
31    /// dummy type required for serde
32    /// see example: <https://serde.rs/deserialize-map.html>
33    struct CustomVisitor;
34    impl<'de> serde::de::Visitor<'de> for CustomVisitor {
35        type Value = Vec<Address>;
36
37        fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38            formatter.write_str("a non-empty list of recipient addresses")
39        }
40
41        fn visit_seq<S>(self, mut access: S) -> Result<Self::Value, S::Error>
42        where
43            S: serde::de::SeqAccess<'de>,
44        {
45            let mut seq: Vec<Address> = Vec::with_capacity(access.size_hint().unwrap_or(0));
46            while let Some(key) = access.next_element()? {
47                seq.push(key);
48            }
49            if seq.is_empty() {
50                Err(serde::de::Error::invalid_length(seq.len(), &self))
51            } else {
52                Ok(seq)
53            }
54        }
55    }
56    pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<Vec<Address>, D::Error>
57    where
58        D: serde::Deserializer<'de>,
59    {
60        deserializer.deserialize_seq(CustomVisitor {})
61    }
62
63    #[cfg(test)]
64    mod tests {
65        #[test]
66        fn deserializing_empty_recipient_list_returns_error() {
67            assert!(
68                serde_json::from_str::<crate::address::Envelope>(r#"{"forward_path": []}"#)
69                    .is_err()
70            );
71        }
72        #[test]
73        fn deserializing_non_empty_recipient_list_is_ok() {
74            serde_json::from_str::<crate::address::Envelope>(
75                r#"{ "forward_path": [ {"user":"foo", "domain":"example.com"} ] }"#,
76            )
77            .unwrap();
78        }
79    }
80}
81
82impl Envelope {
83    /// Creates a new envelope, which may fail if `to` is empty.
84    ///
85    /// # Examples
86    ///
87    /// ```rust
88    /// # use lettre::address::{Address, Envelope};
89    /// # use std::error::Error;
90    /// # fn main() -> Result<(), Box<dyn Error>> {
91    /// let sender = "sender@email.com".parse::<Address>()?;
92    /// let recipients = vec!["to@email.com".parse::<Address>()?];
93    ///
94    /// let envelope = Envelope::new(Some(sender), recipients);
95    /// # Ok(())
96    /// # }
97    /// ```
98    ///
99    /// # Errors
100    ///
101    /// If `to` has no elements in it.
102    pub fn new(from: Option<Address>, to: Vec<Address>) -> Result<Envelope, Error> {
103        if to.is_empty() {
104            return Err(Error::MissingTo);
105        }
106        Ok(Envelope {
107            forward_path: to,
108            reverse_path: from,
109        })
110    }
111
112    /// Gets the destination addresses of the envelope.
113    ///
114    /// # Examples
115    ///
116    /// ```rust
117    /// # use lettre::address::{Address, Envelope};
118    /// # use std::error::Error;
119    /// # fn main() -> Result<(), Box<dyn Error>> {
120    /// let sender = "from@email.com".parse::<Address>()?;
121    /// let recipients = vec!["to@email.com".parse::<Address>()?];
122    ///
123    /// let envelope = Envelope::new(Some(sender), recipients.clone())?;
124    /// assert_eq!(envelope.to(), recipients.as_slice());
125    /// # Ok(())
126    /// # }
127    /// ```
128    pub fn to(&self) -> &[Address] {
129        self.forward_path.as_slice()
130    }
131
132    /// Gets the sender of the envelope.
133    ///
134    /// # Examples
135    ///
136    /// ```rust
137    /// # use lettre::address::{Address, Envelope};
138    /// # use std::error::Error;
139    /// # fn main() -> Result<(), Box<dyn Error>> {
140    /// let sender = "from@email.com".parse::<Address>()?;
141    /// let recipients = vec!["to@email.com".parse::<Address>()?];
142    ///
143    /// let envelope = Envelope::new(Some(sender), recipients.clone())?;
144    /// assert!(envelope.from().is_some());
145    ///
146    /// let senderless = Envelope::new(None, recipients.clone())?;
147    /// assert!(senderless.from().is_none());
148    /// # Ok(())
149    /// # }
150    /// ```
151    pub fn from(&self) -> Option<&Address> {
152        self.reverse_path.as_ref()
153    }
154
155    #[cfg(feature = "smtp-transport")]
156    /// Check if any of the addresses in the envelope contains non-ascii chars
157    pub(crate) fn has_non_ascii_addresses(&self) -> bool {
158        self.reverse_path
159            .iter()
160            .chain(self.forward_path.iter())
161            .any(|a| !a.is_ascii())
162    }
163}
164
165#[cfg(feature = "builder")]
166#[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
167impl TryFrom<&Headers> for Envelope {
168    type Error = Error;
169
170    fn try_from(headers: &Headers) -> Result<Self, Self::Error> {
171        let from = match headers.get::<header::Sender>() {
172            // If there is a Sender, use it
173            Some(sender) => Some(Mailbox::from(sender).email),
174            // ... else try From
175            None => match headers.get::<header::From>() {
176                Some(header::From(a)) => {
177                    let mut from: Vec<Mailbox> = a.into();
178                    if from.len() > 1 {
179                        return Err(Error::TooManyFrom);
180                    }
181                    let from = from.pop().expect("From header has 1 Mailbox");
182                    Some(from.email)
183                }
184                None => None,
185            },
186        };
187
188        fn add_addresses_from_mailboxes(
189            addresses: &mut Vec<Address>,
190            mailboxes: Option<Mailboxes>,
191        ) {
192            if let Some(mailboxes) = mailboxes {
193                addresses.extend(mailboxes.into_iter().map(|mb| mb.email));
194            }
195        }
196        let mut to = vec![];
197        add_addresses_from_mailboxes(&mut to, headers.get::<header::To>().map(|h| h.0));
198        add_addresses_from_mailboxes(&mut to, headers.get::<header::Cc>().map(|h| h.0));
199        add_addresses_from_mailboxes(&mut to, headers.get::<header::Bcc>().map(|h| h.0));
200
201        Self::new(from, to)
202    }
203}