lettre/address/
envelope.rs1use 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#[derive(PartialEq, Eq, Clone, Debug)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Envelope {
14 #[cfg_attr(
18 feature = "serde",
19 serde(deserialize_with = "serde_forward_path::deserialize")
20 )]
21 forward_path: Vec<Address>,
22 reverse_path: Option<Address>,
24}
25
26#[cfg(feature = "serde")]
29mod serde_forward_path {
30 use super::Address;
31 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 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 pub fn to(&self) -> &[Address] {
129 self.forward_path.as_slice()
130 }
131
132 pub fn from(&self) -> Option<&Address> {
152 self.reverse_path.as_ref()
153 }
154
155 #[cfg(feature = "smtp-transport")]
156 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 Some(sender) => Some(Mailbox::from(sender).email),
174 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}