1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::fmt;
5
6use use_email_address::{AddressValidationError, EmailAddress};
7
8#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
10pub struct EnvelopeAddress(EmailAddress);
11
12impl EnvelopeAddress {
13 pub fn new(value: impl AsRef<str>) -> Result<Self, AddressValidationError> {
15 Ok(Self(EmailAddress::new(value)?))
16 }
17
18 #[must_use]
20 pub const fn from_email_address(address: EmailAddress) -> Self {
21 Self(address)
22 }
23
24 #[must_use]
26 pub const fn email_address(&self) -> &EmailAddress {
27 &self.0
28 }
29}
30
31impl From<EmailAddress> for EnvelopeAddress {
32 fn from(value: EmailAddress) -> Self {
33 Self(value)
34 }
35}
36
37impl fmt::Display for EnvelopeAddress {
38 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(formatter, "{}", self.0)
40 }
41}
42
43#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
45pub enum ReversePath {
46 Null,
48 Address(EnvelopeAddress),
50}
51
52impl ReversePath {
53 pub fn new(value: impl AsRef<str>) -> Result<Self, AddressValidationError> {
55 Ok(Self::Address(EnvelopeAddress::new(value)?))
56 }
57
58 #[must_use]
60 pub const fn null() -> Self {
61 Self::Null
62 }
63}
64
65impl fmt::Display for ReversePath {
66 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::Null => formatter.write_str("<>"),
69 Self::Address(address) => write!(formatter, "<{address}>"),
70 }
71 }
72}
73
74#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
76pub struct ForwardPath(EnvelopeAddress);
77
78impl ForwardPath {
79 pub fn new(value: impl AsRef<str>) -> Result<Self, AddressValidationError> {
81 Ok(Self(EnvelopeAddress::new(value)?))
82 }
83
84 #[must_use]
86 pub const fn from_address(address: EnvelopeAddress) -> Self {
87 Self(address)
88 }
89
90 #[must_use]
92 pub const fn address(&self) -> &EnvelopeAddress {
93 &self.0
94 }
95}
96
97impl fmt::Display for ForwardPath {
98 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
99 write!(formatter, "<{}>", self.0)
100 }
101}
102
103#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
105pub struct MailFromPath(ReversePath);
106
107impl MailFromPath {
108 pub fn new(value: impl AsRef<str>) -> Result<Self, AddressValidationError> {
110 Ok(Self(ReversePath::new(value)?))
111 }
112
113 #[must_use]
115 pub const fn null() -> Self {
116 Self(ReversePath::Null)
117 }
118
119 #[must_use]
121 pub const fn reverse_path(&self) -> &ReversePath {
122 &self.0
123 }
124}
125
126impl fmt::Display for MailFromPath {
127 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(formatter, "{}", self.0)
129 }
130}
131
132#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
134pub struct RcptToPath(ForwardPath);
135
136impl RcptToPath {
137 pub fn new(value: impl AsRef<str>) -> Result<Self, AddressValidationError> {
139 Ok(Self(ForwardPath::new(value)?))
140 }
141
142 #[must_use]
144 pub const fn from_forward_path(path: ForwardPath) -> Self {
145 Self(path)
146 }
147
148 #[must_use]
150 pub const fn forward_path(&self) -> &ForwardPath {
151 &self.0
152 }
153}
154
155impl fmt::Display for RcptToPath {
156 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
157 write!(formatter, "{}", self.0)
158 }
159}
160
161#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
163pub struct EnvelopeSender(MailFromPath);
164
165impl EnvelopeSender {
166 pub fn new(value: impl AsRef<str>) -> Result<Self, AddressValidationError> {
168 Ok(Self(MailFromPath::new(value)?))
169 }
170
171 #[must_use]
173 pub const fn null() -> Self {
174 Self(MailFromPath::null())
175 }
176
177 #[must_use]
179 pub const fn path(&self) -> &MailFromPath {
180 &self.0
181 }
182}
183
184impl fmt::Display for EnvelopeSender {
185 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
186 write!(formatter, "{}", self.0)
187 }
188}
189
190#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
192pub struct EnvelopeRecipient(RcptToPath);
193
194impl EnvelopeRecipient {
195 pub fn new(value: impl AsRef<str>) -> Result<Self, AddressValidationError> {
197 Ok(Self(RcptToPath::new(value)?))
198 }
199
200 #[must_use]
202 pub fn from_email_address(address: EmailAddress) -> Self {
203 Self(RcptToPath::from_forward_path(ForwardPath::from_address(
204 EnvelopeAddress::from(address),
205 )))
206 }
207
208 #[must_use]
210 pub const fn path(&self) -> &RcptToPath {
211 &self.0
212 }
213}
214
215impl fmt::Display for EnvelopeRecipient {
216 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
217 write!(formatter, "{}", self.0)
218 }
219}
220
221#[derive(Clone, Debug, Eq, PartialEq)]
223pub struct Envelope {
224 sender: EnvelopeSender,
225 recipients: Vec<EnvelopeRecipient>,
226}
227
228impl Envelope {
229 #[must_use]
231 pub const fn new(sender: EnvelopeSender) -> Self {
232 Self {
233 sender,
234 recipients: Vec::new(),
235 }
236 }
237
238 #[must_use]
240 pub fn with_recipient(mut self, recipient: EnvelopeRecipient) -> Self {
241 self.recipients.push(recipient);
242 self
243 }
244
245 pub fn push_recipient(&mut self, recipient: EnvelopeRecipient) {
247 self.recipients.push(recipient);
248 }
249
250 #[must_use]
252 pub const fn sender(&self) -> &EnvelopeSender {
253 &self.sender
254 }
255
256 #[must_use]
258 pub fn recipients(&self) -> &[EnvelopeRecipient] {
259 &self.recipients
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::{Envelope, EnvelopeRecipient, EnvelopeSender, ReversePath};
266 use use_email_address::AddressValidationError;
267
268 #[test]
269 fn models_envelope_identity() -> Result<(), AddressValidationError> {
270 let envelope = Envelope::new(EnvelopeSender::new("bounce@example.com")?)
271 .with_recipient(EnvelopeRecipient::new("jane@example.com")?);
272
273 assert_eq!(envelope.sender().to_string(), "<bounce@example.com>");
274 assert_eq!(envelope.recipients()[0].to_string(), "<jane@example.com>");
275 assert_eq!(ReversePath::null().to_string(), "<>");
276 Ok(())
277 }
278}