mail_builder/headers/
address.rs1use std::borrow::Cow;
8
9use crate::encoders::encode::rfc2047_encode;
10
11use super::Header;
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
15pub struct EmailAddress<'x> {
16 pub name: Option<Cow<'x, str>>,
17 pub email: Cow<'x, str>,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
22pub struct GroupedAddresses<'x> {
23 pub name: Option<Cow<'x, str>>,
24 pub addresses: Vec<Address<'x>>,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
29pub enum Address<'x> {
30 Address(EmailAddress<'x>),
31 Group(GroupedAddresses<'x>),
32 List(Vec<Address<'x>>),
33}
34
35impl<'x> Address<'x> {
36 pub fn new_address(
38 name: Option<impl Into<Cow<'x, str>>>,
39 email: impl Into<Cow<'x, str>>,
40 ) -> Self {
41 Address::Address(EmailAddress {
42 name: name.map(|v| v.into()),
43 email: email.into(),
44 })
45 }
46
47 pub fn new_group(name: Option<impl Into<Cow<'x, str>>>, addresses: Vec<Address<'x>>) -> Self {
49 Address::Group(GroupedAddresses {
50 name: name.map(|v| v.into()),
51 addresses,
52 })
53 }
54
55 pub fn new_list(items: Vec<Address<'x>>) -> Self {
57 Address::List(items)
58 }
59
60 pub fn unwrap_address(&self) -> &EmailAddress<'x> {
61 match self {
62 Address::Address(address) => address,
63 _ => panic!("Address is not an EmailAddress"),
64 }
65 }
66}
67
68impl<'x> From<(&'x str, &'x str)> for Address<'x> {
69 fn from(value: (&'x str, &'x str)) -> Self {
70 Address::Address(EmailAddress {
71 name: Some(value.0.into()),
72 email: value.1.into(),
73 })
74 }
75}
76
77impl From<(String, String)> for Address<'_> {
78 fn from(value: (String, String)) -> Self {
79 Address::Address(EmailAddress {
80 name: Some(value.0.into()),
81 email: value.1.into(),
82 })
83 }
84}
85
86impl<'x> From<&'x str> for Address<'x> {
87 fn from(value: &'x str) -> Self {
88 Address::Address(EmailAddress {
89 name: None,
90 email: value.into(),
91 })
92 }
93}
94
95impl From<String> for Address<'_> {
96 fn from(value: String) -> Self {
97 Address::Address(EmailAddress {
98 name: None,
99 email: value.into(),
100 })
101 }
102}
103
104impl<'x, T> From<Vec<T>> for Address<'x>
105where
106 T: Into<Address<'x>>,
107{
108 fn from(value: Vec<T>) -> Self {
109 Address::new_list(value.into_iter().map(|x| x.into()).collect())
110 }
111}
112
113impl<'x, T, U> From<(U, Vec<T>)> for Address<'x>
114where
115 T: Into<Address<'x>>,
116 U: Into<Cow<'x, str>>,
117{
118 fn from(value: (U, Vec<T>)) -> Self {
119 Address::Group(GroupedAddresses {
120 name: Some(value.0.into()),
121 addresses: value.1.into_iter().map(|x| x.into()).collect(),
122 })
123 }
124}
125
126impl Header for Address<'_> {
127 fn write_header(
128 &self,
129 mut output: impl std::io::Write,
130 mut bytes_written: usize,
131 ) -> std::io::Result<usize> {
132 match self {
133 Address::Address(address) => {
134 address.write_header(&mut output, bytes_written)?;
135 }
136 Address::Group(group) => {
137 group.write_header(&mut output, bytes_written)?;
138 }
139 Address::List(list) => {
140 for (pos, address) in list.iter().enumerate() {
141 if bytes_written
142 + (match address {
143 Address::Address(address) => {
144 address.email.len()
145 + address.name.as_ref().map_or(0, |n| n.len() + 3)
146 + 2
147 }
148 Address::Group(group) => {
149 group.name.as_ref().map_or(0, |name| name.len() + 2)
150 }
151 Address::List(_) => 0,
152 })
153 >= 76
154 {
155 output.write_all(b"\r\n\t")?;
156 bytes_written = 1;
157 }
158
159 match address {
160 Address::Address(address) => {
161 bytes_written += address.write_header(&mut output, bytes_written)?;
162 if pos < list.len() - 1 {
163 output.write_all(b", ")?;
164 bytes_written += 1;
165 }
166 }
167 Address::Group(group) => {
168 bytes_written += group.write_header(&mut output, bytes_written)?;
169 if pos < list.len() - 1 {
170 output.write_all(b" ")?;
171 bytes_written += 1;
172 }
173 }
174 Address::List(_) => unreachable!(),
175 }
176 }
177 }
178 }
179 output.write_all(b"\r\n")?;
180 Ok(0)
181 }
182}
183
184impl Header for EmailAddress<'_> {
185 fn write_header(
186 &self,
187 mut output: impl std::io::Write,
188 mut bytes_written: usize,
189 ) -> std::io::Result<usize> {
190 if let Some(name) = &self.name {
191 bytes_written += rfc2047_encode(name, &mut output)?;
192 if bytes_written + self.email.len() + 2 >= 76 {
193 output.write_all(b"\r\n\t")?;
194 bytes_written = 1;
195 } else {
196 output.write_all(b" ")?;
197 bytes_written += 1;
198 }
199 }
200
201 output.write_all(b"<")?;
202 output.write_all(self.email.as_bytes())?;
203 output.write_all(b">")?;
204
205 Ok(bytes_written + self.email.len() + 2)
206 }
207}
208
209impl Header for GroupedAddresses<'_> {
210 fn write_header(
211 &self,
212 mut output: impl std::io::Write,
213 mut bytes_written: usize,
214 ) -> std::io::Result<usize> {
215 if let Some(name) = &self.name {
216 bytes_written += rfc2047_encode(name, &mut output)? + 2;
217 output.write_all(b": ")?;
218 }
219
220 for (pos, address) in self.addresses.iter().enumerate() {
221 let address = address.unwrap_address();
222
223 if bytes_written
224 + address.email.len()
225 + address.name.as_ref().map_or(0, |n| n.len() + 3)
226 + 2
227 >= 76
228 {
229 output.write_all(b"\r\n\t")?;
230 bytes_written = 1;
231 }
232
233 bytes_written += address.write_header(&mut output, bytes_written)?;
234 if pos < self.addresses.len() - 1 {
235 output.write_all(b", ")?;
236 bytes_written += 2;
237 }
238 }
239
240 output.write_all(b";")?;
241 bytes_written += 1;
242
243 Ok(bytes_written)
244 }
245}