1use email_encoding::headers::writer::EmailWriter;
2
3use super::{Header, HeaderName, HeaderValue};
4use crate::{
5 message::mailbox::{Mailbox, Mailboxes},
6 BoxError,
7};
8
9pub trait MailboxesHeader {
11 fn join_mailboxes(&mut self, other: Self);
12}
13
14macro_rules! mailbox_header {
15 ($(#[$doc:meta])*($type_name: ident, $header_name: expr)) => {
16 $(#[$doc])*
17 #[derive(Debug, Clone, PartialEq, Eq)]
18 pub struct $type_name(Mailbox);
19
20 impl Header for $type_name {
21 fn name() -> HeaderName {
22 HeaderName::new_from_ascii_str($header_name)
23 }
24
25 fn parse(s: &str) -> Result<Self, BoxError> {
26 let mailbox: Mailbox = s.parse()?;
27 Ok(Self(mailbox))
28 }
29
30 fn display(&self) -> HeaderValue {
31 let mut encoded_value = String::new();
32 let line_len = $header_name.len() + ": ".len();
33 {
34 let mut w = EmailWriter::new(&mut encoded_value, line_len, 0, false);
35 self.0.encode(&mut w).expect("writing `Mailbox` returned an error");
36 }
37
38 HeaderValue::dangerous_new_pre_encoded(Self::name(), self.0.to_string(), encoded_value)
39 }
40 }
41
42 impl std::convert::From<Mailbox> for $type_name {
43 #[inline]
44 fn from(mailbox: Mailbox) -> Self {
45 Self(mailbox)
46 }
47 }
48
49 impl std::convert::From<$type_name> for Mailbox {
50 #[inline]
51 fn from(this: $type_name) -> Mailbox {
52 this.0
53 }
54 }
55 };
56}
57
58macro_rules! mailboxes_header {
59 ($(#[$doc:meta])*($type_name: ident, $header_name: expr)) => {
60 $(#[$doc])*
61 #[derive(Debug, Clone, PartialEq, Eq)]
62 pub struct $type_name(pub(crate) Mailboxes);
63
64 impl MailboxesHeader for $type_name {
65 fn join_mailboxes(&mut self, other: Self) {
66 self.0.extend(other.0);
67 }
68 }
69
70 impl Header for $type_name {
71 fn name() -> HeaderName {
72 HeaderName::new_from_ascii_str($header_name)
73 }
74
75 fn parse(s: &str) -> Result<Self, BoxError> {
76 let mailbox: Mailboxes = s.parse()?;
77 Ok(Self(mailbox))
78 }
79
80 fn display(&self) -> HeaderValue {
81 let mut encoded_value = String::new();
82 let line_len = $header_name.len() + ": ".len();
83 {
84 let mut w = EmailWriter::new(&mut encoded_value, line_len, 0, false);
85 self.0.encode(&mut w).expect("writing `Mailboxes` returned an error");
86 }
87
88 HeaderValue::dangerous_new_pre_encoded(Self::name(), self.0.to_string(), encoded_value)
89 }
90 }
91
92 impl std::convert::From<Mailboxes> for $type_name {
93 #[inline]
94 fn from(mailboxes: Mailboxes) -> Self {
95 Self(mailboxes)
96 }
97 }
98
99 impl std::convert::From<$type_name> for Mailboxes {
100 #[inline]
101 fn from(this: $type_name) -> Mailboxes {
102 this.0
103 }
104 }
105 };
106}
107
108mailbox_header! {
109 (Sender, "Sender")
120}
121
122mailboxes_header! {
123 (From, "From")
131}
132
133mailboxes_header! {
134 (ReplyTo, "Reply-To")
142}
143
144mailboxes_header! {
145 (To, "To")
153}
154
155mailboxes_header! {
156 (Cc, "Cc")
164}
165
166mailboxes_header! {
167 (Bcc, "Bcc")
175}
176
177#[cfg(test)]
178mod test {
179 use pretty_assertions::assert_eq;
180
181 use super::{From, Mailbox, Mailboxes};
182 use crate::message::header::{HeaderName, HeaderValue, Headers};
183
184 #[test]
185 fn format_single_without_name() {
186 let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
187
188 let mut headers = Headers::new();
189 headers.set(From(from));
190
191 assert_eq!(headers.to_string(), "From: kayo@example.com\r\n");
192 }
193
194 #[test]
195 fn format_single_with_name() {
196 let from = Mailboxes::new().with("Kayo <kayo@example.com>".parse().unwrap());
197
198 let mut headers = Headers::new();
199 headers.set(From(from));
200
201 assert_eq!(headers.to_string(), "From: Kayo <kayo@example.com>\r\n");
202 }
203
204 #[test]
205 fn format_multi_without_name() {
206 let from = Mailboxes::new()
207 .with("kayo@example.com".parse().unwrap())
208 .with("pony@domain.tld".parse().unwrap());
209
210 let mut headers = Headers::new();
211 headers.set(From(from));
212
213 assert_eq!(
214 headers.to_string(),
215 "From: kayo@example.com, pony@domain.tld\r\n"
216 );
217 }
218
219 #[test]
220 fn format_multi_with_name() {
221 let from = vec![
222 "Kayo <kayo@example.com>".parse().unwrap(),
223 "Pony P. <pony@domain.tld>".parse().unwrap(),
224 ];
225
226 let mut headers = Headers::new();
227 headers.set(From(from.into()));
228
229 assert_eq!(
230 headers.to_string(),
231 "From: Kayo <kayo@example.com>, \"Pony P.\" <pony@domain.tld>\r\n"
232 );
233 }
234
235 #[test]
236 fn format_single_with_utf8_name() {
237 let from = vec!["Кайо <kayo@example.com>".parse().unwrap()];
238
239 let mut headers = Headers::new();
240 headers.set(From(from.into()));
241
242 assert_eq!(
243 headers.to_string(),
244 "From: =?utf-8?b?0JrQsNC50L4=?= <kayo@example.com>\r\n"
245 );
246 }
247
248 #[test]
249 fn parse_single_without_name() {
250 let from = vec!["kayo@example.com".parse().unwrap()].into();
251
252 let mut headers = Headers::new();
253 headers.insert_raw(HeaderValue::new(
254 HeaderName::new_from_ascii_str("From"),
255 "kayo@example.com".to_owned(),
256 ));
257
258 assert_eq!(headers.get::<From>(), Some(From(from)));
259 }
260
261 #[test]
262 fn parse_single_with_name() {
263 let from = vec!["K. <kayo@example.com>".parse().unwrap()].into();
264
265 let mut headers = Headers::new();
266 headers.insert_raw(HeaderValue::new(
267 HeaderName::new_from_ascii_str("From"),
268 "K. <kayo@example.com>".to_owned(),
269 ));
270
271 assert_eq!(headers.get::<From>(), Some(From(from)));
272 }
273
274 #[test]
275 fn parse_multi_without_name() {
276 let from: Vec<Mailbox> = vec![
277 "kayo@example.com".parse().unwrap(),
278 "pony@domain.tld".parse().unwrap(),
279 ];
280
281 let mut headers = Headers::new();
282 headers.insert_raw(HeaderValue::new(
283 HeaderName::new_from_ascii_str("From"),
284 "kayo@example.com, pony@domain.tld".to_owned(),
285 ));
286
287 assert_eq!(headers.get::<From>(), Some(From(from.into())));
288 }
289
290 #[test]
291 fn parse_multi_with_name() {
292 let from: Vec<Mailbox> = vec![
293 "K. <kayo@example.com>".parse().unwrap(),
294 "Pony P. <pony@domain.tld>".parse().unwrap(),
295 ];
296
297 let mut headers = Headers::new();
298 headers.insert_raw(HeaderValue::new(
299 HeaderName::new_from_ascii_str("From"),
300 "K. <kayo@example.com>, Pony P. <pony@domain.tld>".to_owned(),
301 ));
302
303 assert_eq!(headers.get::<From>(), Some(From(from.into())));
304 }
305
306 #[test]
307 fn parse_multi_with_name_containing_comma() {
308 let from: Vec<Mailbox> = vec![
309 "\"Test, test\" <1@example.com>".parse().unwrap(),
310 "\"Test2, test2\" <2@example.com>".parse().unwrap(),
311 ];
312
313 let mut headers = Headers::new();
314 headers.insert_raw(HeaderValue::new(
315 HeaderName::new_from_ascii_str("From"),
316 "\"Test, test\" <1@example.com>, \"Test2, test2\" <2@example.com>".to_owned(),
317 ));
318
319 assert_eq!(headers.get::<From>(), Some(From(from.into())));
320 }
321
322 #[test]
323 fn parse_multi_with_name_containing_double_quotes() {
324 let from: Vec<Mailbox> = vec![
325 "\"Test, test\" <1@example.com>".parse().unwrap(),
326 "\"Test2, \"test2\"\" <2@example.com>".parse().unwrap(),
327 ];
328
329 let mut headers = Headers::new();
330 headers.insert_raw(HeaderValue::new(
331 HeaderName::new_from_ascii_str("From"),
332 "\"Test, test\" <1@example.com>, \"Test2, \"test2\"\" <2@example.com>".to_owned(),
333 ));
334
335 assert_eq!(headers.get::<From>(), Some(From(from.into())));
336 }
337
338 #[test]
339 fn parse_multi_with_name_containing_comma_last_broken() {
340 let mut headers = Headers::new();
341 headers.insert_raw(HeaderValue::new(
342 HeaderName::new_from_ascii_str("From"),
343 "\"Test, test\" <1@example.com>, \"Test2, test2\"".to_owned(),
344 ));
345
346 assert_eq!(headers.get::<From>(), None);
347 }
348
349 #[test]
350 fn mailbox_format_address_with_angle_bracket() {
351 assert_eq!(
352 format!(
353 "{}",
354 Mailbox::new(Some("<3".into()), "i@love.example".parse().unwrap())
355 ),
356 r#""<3" <i@love.example>"#
357 );
358 }
359}