dust_mail/client/
builder.rs1use std::{collections::HashMap, fmt::Display, result};
2
3use crate::error::{err, Error, ErrorKind, Result};
4
5use super::{address::Address, content::Content, incoming::types::flag::Flag, parser, Headers};
6
7#[derive(Debug)]
8pub struct MessageBuilder {
9 pub(crate) from: Option<Address>,
10 pub(crate) to: Option<Address>,
11 pub(crate) cc: Option<Address>,
12 pub(crate) bcc: Option<Address>,
13 pub(crate) flags: Vec<Flag>,
14 pub(crate) id: Option<String>,
15 pub(crate) sent: Option<i64>,
16 pub(crate) subject: Option<String>,
17 pub(crate) headers: Option<Headers>,
18 pub(crate) content: Content,
19}
20
21#[cfg(feature = "maildir")]
22impl TryFrom<maildir::MailEntry> for MessageBuilder {
23 type Error = Error;
24
25 fn try_from(mut mail_entry: maildir::MailEntry) -> result::Result<Self, Self::Error> {
26 let parsed = mail_entry.parsed()?;
27
28 let mut builder = parser::message::from_parsed_mail(parsed)?;
29
30 if mail_entry.is_seen() {
31 builder = builder.flag(Flag::Read);
32 }
33
34 if mail_entry.is_flagged() {
35 builder = builder.flag(Flag::Flagged);
36 }
37
38 if mail_entry.is_draft() {
39 builder = builder.flag(Flag::Draft);
40 }
41
42 if mail_entry.is_trashed() {
43 builder = builder.flag(Flag::Deleted);
44 }
45
46 if mail_entry.is_replied() {
47 builder = builder.flag(Flag::Answered);
48 }
49
50 Ok(builder)
51 }
52}
53
54impl TryFrom<&[u8]> for MessageBuilder {
55 type Error = Error;
56
57 fn try_from(bytes: &[u8]) -> result::Result<Self, Self::Error> {
58 parser::message::from_rfc822(bytes)
59 }
60}
61
62impl MessageBuilder {
63 pub fn new() -> Self {
64 Self {
65 flags: Vec::new(),
66 from: None,
67 bcc: None,
68 cc: None,
69 to: None,
70 id: None,
71 sent: None,
72 subject: None,
73 content: Content::default(),
74 headers: None,
75 }
76 }
77
78 pub fn flags<F: IntoIterator<Item = Flag>>(mut self, flags: F) -> Self {
79 let mut iter = flags.into_iter();
80
81 while let Some(flag) = iter.next() {
82 self.flags.push(flag)
83 }
84
85 self
86 }
87
88 pub fn flag(mut self, flag: Flag) -> Self {
89 self.flags.push(flag);
90
91 self
92 }
93
94 pub fn senders<C: Into<Address>>(mut self, sender: C) -> Self {
95 self.from = Some(sender.into());
96
97 self
98 }
99
100 pub fn recipients<C: Into<Address>>(mut self, recipient: C) -> Self {
101 self.to = Some(recipient.into());
102
103 self
104 }
105
106 pub fn cc<C: Into<Address>>(mut self, cc: C) -> Self {
107 self.cc = Some(cc.into());
108
109 self
110 }
111
112 pub fn bcc<C: Into<Address>>(mut self, bcc: C) -> Self {
113 self.bcc = Some(bcc.into());
114
115 self
116 }
117
118 pub fn id<I: Display>(mut self, id: I) -> Self {
119 self.id = Some(id.to_string());
120
121 self
122 }
123
124 pub fn sent(mut self, sent: i64) -> Self {
125 self.sent = Some(sent);
126
127 self
128 }
129
130 pub fn subject<S: Display>(mut self, subject: S) -> Self {
131 self.subject = Some(subject.to_string());
132
133 self
134 }
135
136 pub fn headers(mut self, headers: Headers) -> Self {
137 self.headers = Some(headers);
138
139 self
140 }
141
142 pub fn header<H: Into<String>, V: Display>(mut self, header: H, value: V) -> Self {
143 if let None = self.headers {
144 self.headers = Some(HashMap::new());
145 }
146
147 if let Some(headers) = self.headers.as_mut() {
148 headers.insert(header.into(), value.to_string());
149 }
150
151 self
152 }
153
154 pub fn html<H: Into<String>>(mut self, html: H) -> Self {
155 self.content.set_html(html);
156
157 self
158 }
159
160 pub fn text<H: Into<String>>(mut self, text: H) -> Self {
161 self.content.set_text(text);
162
163 self
164 }
165
166 pub fn build<T: TryFrom<Self>>(self) -> Result<T> {
167 match self.try_into() {
168 Ok(message) => Ok(message),
169 Err(_err) => err!(ErrorKind::InvalidMessage, "Could not build a valid message"),
170 }
171 }
172}