1use super::{Body, Mailbox};
2use bytes::{BufMut, Bytes, BytesMut, IntoBuf};
3use encoder::{EncoderError, EncoderStream};
4use futures::{Async, Poll, Stream};
5use header::{self, EmailDate, Header, Headers, MailboxesHeader};
6use hyper::body::Payload;
7use std::fmt::{Display, Formatter, Result as FmtResult};
8use std::mem::replace;
9use std::time::SystemTime;
10
11#[derive(Debug, Clone)]
13pub struct MessageBuilder {
14 headers: Headers,
15}
16
17impl MessageBuilder {
18 #[inline]
20 pub fn new() -> Self {
21 Self {
22 headers: Headers::new(),
23 }
24 }
25
26 #[inline]
28 pub fn header<H: Header>(mut self, header: H) -> Self {
29 self.headers.set(header);
30 self
31 }
32
33 pub fn mailbox<H: Header + MailboxesHeader>(mut self, header: H) -> Self {
35 if self.headers.has::<H>() {
36 self.headers.get_mut::<H>().unwrap().join_mailboxes(header);
37 self
38 } else {
39 self.header(header)
40 }
41 }
42
43 #[inline]
47 pub fn date(self, date: EmailDate) -> Self {
48 self.header(header::Date(date))
49 }
50
51 #[inline]
55 pub fn date_now(self) -> Self {
56 self.date(SystemTime::now().into())
57 }
58
59 #[inline]
63 pub fn subject<S: Into<String>>(self, subject: S) -> Self {
64 self.header(header::Subject(subject.into()))
65 }
66
67 #[inline]
71 pub fn mime_1_0(self) -> Self {
72 self.header(header::MIME_VERSION_1_0)
73 }
74
75 #[inline]
79 pub fn sender(self, mbox: Mailbox) -> Self {
80 self.header(header::Sender(mbox))
81 }
82
83 #[inline]
87 pub fn from(self, mbox: Mailbox) -> Self {
88 self.mailbox(header::From(mbox.into()))
89 }
90
91 #[inline]
95 pub fn reply_to(self, mbox: Mailbox) -> Self {
96 self.mailbox(header::ReplyTo(mbox.into()))
97 }
98
99 #[inline]
103 pub fn to(self, mbox: Mailbox) -> Self {
104 self.mailbox(header::To(mbox.into()))
105 }
106
107 #[inline]
111 pub fn cc(self, mbox: Mailbox) -> Self {
112 self.mailbox(header::Cc(mbox.into()))
113 }
114
115 #[inline]
119 pub fn bcc(self, mbox: Mailbox) -> Self {
120 self.mailbox(header::Bcc(mbox.into()))
121 }
122
123 #[inline]
125 pub fn body<T>(self, body: T) -> Message<T> {
126 Message {
127 headers: self.headers,
128 split: true,
129 body,
130 }
131 }
132
133 #[inline]
135 pub fn join<T>(self, body: T) -> Message<T> {
136 Message {
137 headers: self.headers,
138 split: false,
139 body,
140 }
141 }
142
143 #[inline]
147 pub fn mime_body<T>(self, body: T) -> Message<T> {
148 self.mime_1_0().join(body)
149 }
150}
151
152#[derive(Clone, Debug)]
154pub struct Message<B = Body> {
155 headers: Headers,
156 split: bool,
157 body: B,
158}
159
160impl Message<()> {
161 #[inline]
163 pub fn builder() -> MessageBuilder {
164 MessageBuilder::new()
165 }
166
167 #[inline]
169 pub fn create() -> MessageBuilder {
170 Self::builder().date_now()
171 }
172}
173
174impl<B> Message<B> {
175 #[inline]
177 pub fn headers(&self) -> &Headers {
178 &self.headers
179 }
180
181 #[inline]
183 pub fn headers_mut(&mut self) -> &mut Headers {
184 &mut self.headers
185 }
186
187 #[inline]
189 pub fn set_body<T: Into<B>>(&mut self, body: T) {
190 self.body = body.into();
191 }
192
193 #[inline]
195 pub fn body_ref(&self) -> &B {
196 &self.body
197 }
198
199 pub fn into_stream(self) -> MessageStream<B>
201 where
202 B: Payload,
203 {
204 self.into()
205 }
206}
207
208pub struct MessageStream<B> {
210 headers: Option<Headers>,
211 split: bool,
212 body: Option<EncoderStream<B>>,
213}
214
215impl<B> Stream for MessageStream<B>
216where
217 B: Payload,
218 B::Data: IntoBuf,
219{
220 type Item = Bytes;
221 type Error = EncoderError<B::Error>;
222
223 fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
224 if self.headers.is_none() {
225 let res = if let Some(body) = &mut self.body {
227 body.poll()
228 } else {
229 return Ok(Async::Ready(None));
231 };
232
233 return if let Ok(Async::Ready(None)) = &res {
234 self.body = None;
236 Ok(Async::Ready(None))
237 } else {
238 res
240 };
241 }
242
243 let headers = replace(&mut self.headers, None).unwrap().to_string();
245 let mut out = BytesMut::with_capacity(headers.len() + if self.split { 2 } else { 0 });
246 out.put(&headers);
247 if self.split {
248 out.put_slice(b"\r\n");
249 }
250 Ok(Async::Ready(Some(out.freeze())))
251 }
252}
253
254impl<B> From<Message<B>> for MessageStream<B>
257where
258 B: Payload,
259{
260 fn from(
261 Message {
262 headers,
263 split,
264 body,
265 }: Message<B>,
266 ) -> Self {
267 let body = {
268 let encoding = headers.get();
269 EncoderStream::wrap(encoding, body)
270 };
271
272 MessageStream {
273 headers: Some(headers),
274 split,
275 body: Some(body),
276 }
277 }
278}
279
280impl Default for MessageBuilder {
281 fn default() -> Self {
282 MessageBuilder::new()
283 }
284}
285
286impl<B> Display for Message<B>
287where
288 B: Display,
289{
290 fn fmt(&self, f: &mut Formatter) -> FmtResult {
291 self.headers.fmt(f)?;
292 if self.split {
293 f.write_str("\r\n")?;
294 }
295 self.body.fmt(f)
296 }
297}
298
299#[cfg(test)]
300mod test {
301 use header;
302 use mailbox::Mailbox;
303 use message::Message;
304
305 use futures::{Future, Stream};
306 use std::str::from_utf8;
307
308 #[test]
309 fn date_header() {
310 let date = "Tue, 15 Nov 1994 08:12:31 GMT".parse().unwrap();
311
312 let email = Message::builder().date(date).body("");
313
314 assert_eq!(
315 format!("{}", email),
316 "Date: Tue, 15 Nov 1994 08:12:31 GMT\r\n\r\n"
317 );
318 }
319
320 #[test]
321 fn email_message() {
322 let date = "Tue, 15 Nov 1994 08:12:31 GMT".parse().unwrap();
323
324 let email = Message::builder()
325 .date(date)
326 .header(header::From(
327 vec![Mailbox::new(
328 Some("Каи".into()),
329 "kayo@example.com".parse().unwrap(),
330 )].into(),
331 )).header(header::To(
332 vec!["Pony O.P. <pony@domain.tld>".parse().unwrap()].into(),
333 )).header(header::Subject("яңа ел белән!".into()))
334 .body("Happy new year!");
335
336 assert_eq!(
337 format!("{}", email),
338 concat!(
339 "Date: Tue, 15 Nov 1994 08:12:31 GMT\r\n",
340 "From: =?utf-8?b?0JrQsNC4?= <kayo@example.com>\r\n",
341 "To: Pony O.P. <pony@domain.tld>\r\n",
342 "Subject: =?utf-8?b?0Y/So9CwINC10Lsg0LHQtdC705nQvSE=?=\r\n",
343 "\r\n",
344 "Happy new year!"
345 )
346 );
347 }
348
349 #[test]
350 fn message_to_stream() {
351 let date = "Tue, 15 Nov 1994 08:12:31 GMT".parse().unwrap();
352
353 let email: Message = Message::builder()
354 .date(date)
355 .header(header::From(
356 vec![Mailbox::new(
357 Some("Каи".into()),
358 "kayo@example.com".parse().unwrap(),
359 )].into(),
360 )).header(header::To(
361 vec!["Pony O.P. <pony@domain.tld>".parse().unwrap()].into(),
362 )).header(header::Subject("яңа ел белән!".into()))
363 .body("Happy new year!".into());
364
365 let body = email.into_stream();
366
367 assert_eq!(
368 body.concat2()
369 .map(|b| String::from(from_utf8(&b).unwrap()))
370 .wait()
371 .unwrap(),
372 concat!(
373 "Date: Tue, 15 Nov 1994 08:12:31 GMT\r\n",
374 "From: =?utf-8?b?0JrQsNC4?= <kayo@example.com>\r\n",
375 "To: Pony O.P. <pony@domain.tld>\r\n",
376 "Subject: =?utf-8?b?0Y/So9CwINC10Lsg0LHQtdC705nQvSE=?=\r\n",
377 "\r\n",
378 "Happy new year!"
379 )
380 );
381 }
382}