Skip to main content

mail_builder/headers/
message_id.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: Apache-2.0 OR MIT
5 */
6
7use super::{Header, fold::FoldWriter};
8use crate::{mime::write_boundary, writer::Writer};
9use std::borrow::Cow;
10
11/// RFC5322 Message ID header
12#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
13pub struct MessageId<'x> {
14    pub id: Vec<Cow<'x, str>>,
15}
16
17impl<'x> MessageId<'x> {
18    /// Create a new Message ID header
19    pub fn new(id: impl Into<Cow<'x, str>>) -> Self {
20        Self {
21            id: vec![id.into()],
22        }
23    }
24
25    /// Create a new multi-value Message ID header
26    pub fn new_list<T, U>(ids: T) -> Self
27    where
28        T: Iterator<Item = U>,
29        U: Into<Cow<'x, str>>,
30    {
31        Self {
32            id: ids.map(|s| s.into()).collect(),
33        }
34    }
35}
36
37impl<'x> From<&'x str> for MessageId<'x> {
38    fn from(value: &'x str) -> Self {
39        Self::new(value)
40    }
41}
42
43impl From<String> for MessageId<'_> {
44    fn from(value: String) -> Self {
45        Self::new(value)
46    }
47}
48
49impl<'x> From<&[&'x str]> for MessageId<'x> {
50    fn from(value: &[&'x str]) -> Self {
51        MessageId {
52            id: value.iter().map(|&s| s.into()).collect(),
53        }
54    }
55}
56
57impl<'x> From<&'x [String]> for MessageId<'x> {
58    fn from(value: &'x [String]) -> Self {
59        MessageId {
60            id: value.iter().map(|s| s.into()).collect(),
61        }
62    }
63}
64
65impl<'x, T> From<Vec<T>> for MessageId<'x>
66where
67    T: Into<Cow<'x, str>>,
68{
69    fn from(value: Vec<T>) -> Self {
70        MessageId {
71            id: value.into_iter().map(|s| s.into()).collect(),
72        }
73    }
74}
75
76pub fn generate_message_id_header(output: &mut impl Writer, hostname: &str) {
77    output.write_byte(b'<');
78    write_boundary(output, ".");
79    output.write_byte(b'@');
80    output.write(hostname.as_bytes());
81    output.write_byte(b'>');
82}
83
84impl Header for MessageId<'_> {
85    fn write_header(&self, output: &mut impl Writer, column: usize) {
86        let Some((last, head)) = self.id.split_last() else {
87            output.write(b"\r\n");
88            return;
89        };
90
91        let mut folder = FoldWriter::new(output, column);
92
93        for id in head {
94            folder.begin_atom(id.len() + 2);
95            folder.write_byte(b'<');
96            folder.write(id.as_bytes());
97            folder.write_byte(b'>');
98            folder.space();
99        }
100
101        folder.begin_atom(last.len() + 2);
102        folder.write_byte(b'<');
103        folder.write(last.as_bytes());
104        folder.write(b">\r\n");
105    }
106}