email_format/
lib.rs

1//! # email-format
2//!
3//! This crate allows you to construct email messages in a way that assures that
4//! they are compliant with relevant email standards (especially RFC 5322). Invalid
5//! data submitted will return a ParseError.
6//!
7//! The main structure to work with is `Email`. It has many functions to set or add
8//! headers and to set the body. All of these will accept an `&str` or `&[u8]` argument
9//! and attempt to parse it. These setters return a `Result<(), ParseError>` as the
10//! parse may fail.
11//!
12//! ## Composition
13//!
14//! You can compose an email like this:
15//!
16//! ```
17//! use email_format::Email;
18//!
19//! let mut email = Email::new(
20//!     "myself@mydomain.com",  // "From:"
21//!     "Wed, 5 Jan 2015 15:13:05 +1300" // "Date:"
22//! ).unwrap();
23//! email.set_sender("from_myself@mydomain.com").unwrap();
24//! email.set_reply_to("My Mailer <no-reply@mydomain.com>").unwrap();
25//! email.set_to("You <you@yourdomain.com>").unwrap();
26//! email.set_cc("Our Friend <friend@frienddomain.com>").unwrap();
27//! email.set_message_id("<id/20161128115731.29084.maelstrom@mydomain.com>").unwrap();
28//! email.set_subject("Hello Friend").unwrap();
29//! email.set_body("Good to hear from you.\r\n\
30//!                 I wish you the best.\r\n\
31//!                 \r\n\
32//!                 Your Friend").unwrap();
33//!
34//! println!("{}", email);
35//! ```
36//!
37//! This outputs:
38//!
39//! ```text
40//! Date:Wed, 5 Jan 2015 15:13:05 +1300
41//! From:myself@mydomain.com
42//! Sender:from_myself@mydomain.com
43//! Reply-To:My Mailer <no-reply@mydomain.com>
44//! To:You <you@yourdomain.com>
45//! Cc:Our Friend <friend@frienddomain.com>
46//! Message-ID:<id/20161128115731.29084.maelstrom@mydomain.com>
47//! Subject:Hello Friend
48//!
49//! Good to hear from you.
50//! I wish you the best.
51//!
52//! Your Friend
53//! ```
54//!
55//! ## Parsing
56//!
57//! The following code will parse the input bytes (or panic if the parse
58//! failed), and leave any trailing bytes in the remainder, which should
59//! be checked to verify it is empty.
60//!
61//! ```
62//! use email_format::Email;
63//! use email_format::rfc5322::Parsable;
64//!
65//! let input = "Date: Wed, 5 Jan 2015 15:13:05 +1300\r\n\
66//!              From: myself@mydomain.com\r\n\
67//!              Sender: from_myself@mydomain.com\r\n\
68//!              My-Crazy-Field: this is my field\r\n\
69//!              Subject: Hello Friend\r\n\
70//!              \r\n\
71//!              Good to hear from you.\r\n\
72//!              I wish you the best.\r\n\
73//!              \r\n\
74//!              Your Friend".as_bytes();
75//!  let (mut email, remainder) = Email::parse(&input).unwrap();
76//!  assert_eq!(remainder.len(), 0);
77//! ```
78//!
79//! ## Usage with lettre and/or mailstrom
80//!
81//! If compiled with the `lettre` feature, you can generate a `SendableEmail`
82//! like this, and then use the `lettre` crate (or `mailstrom`) to send it.
83//!
84//! ```ignore
85//! let sendable_email = email.as_sendable_email().unwrap();
86//! ```
87
88extern crate buf_read_ext;
89
90#[cfg(feature="time")]
91extern crate time;
92#[cfg(feature="chrono")]
93extern crate chrono;
94#[cfg(feature="lettre")]
95extern crate lettre;
96
97#[cfg(test)]
98mod tests;
99
100/// This module contains nitty-gritty details about parsing, storage, and streaming
101/// an `Email`.
102pub mod rfc5322;
103
104use std::io::Write;
105use std::io::Error as IoError;
106use std::fmt;
107
108use rfc5322::{Message, Fields, Field};
109use rfc5322::{Parsable, Streamable};
110use rfc5322::error::ParseError;
111use rfc5322::Body;
112use rfc5322::headers::{From, OrigDate, Sender, ReplyTo, To, Cc, Bcc, MessageId,
113                           InReplyTo, References, Subject, Comments, Keywords,
114                           OptionalField};
115
116/// Attempt to construct `Self` via a conversion (borrowed from rust `std`)
117///
118/// This TryFrom trait is defined in the rust std library but is behind a
119/// feature gate.  We place it here so that people using stable compilers
120/// can still use our crate.  In the future, the std trait should be used.
121pub trait TryFrom<T>: Sized {
122    /// The type returned in the event of a conversion error.
123    type Error;
124
125    /// Performs the conversion.
126    fn try_from(_: T) -> Result<Self, Self::Error>;
127}
128
129// We implement TryFrom from T to T with our ParseError for crate ergonomics
130// (Rust won't let it be implemented with an unconstrained error type)
131impl<T> TryFrom<T> for T {
132    type Error = ::rfc5322::error::ParseError;
133    fn try_from(input: T) -> Result<T, Self::Error> {
134        Ok(input)
135    }
136}
137
138#[derive(Debug, Clone)]
139pub struct Email {
140    message: Message,
141}
142
143impl Email {
144    /// Create a new email structure.  The `From` address and `Date` fields are
145    /// required in all valid emails, thus you must pass these in.
146    pub fn new<F,D>(from: F, date: D) -> Result<Email, ParseError>
147        where From: TryFrom<F, Error=ParseError>, OrigDate: TryFrom<D, Error=ParseError>
148    {
149        Ok(Email {
150            message: Message {
151                fields: Fields {
152                    trace_blocks: vec![],
153                    fields: vec![
154                        Field::OrigDate(TryFrom::try_from(date)?),
155                        Field::From(TryFrom::try_from(from)?) ],
156                },
157                body: None,
158            }
159        })
160    }
161
162    /// Replace the `Date` field in the email
163    pub fn set_date<D>(&mut self, date: D) -> Result<(), ParseError>
164        where OrigDate: TryFrom<D, Error=ParseError>
165    {
166        let value: OrigDate = TryFrom::try_from(date)?;
167        for field in self.message.fields.fields.iter_mut() {
168            if let Field::OrigDate(_) = *field {
169                *field = Field::OrigDate(value);
170                return Ok(())
171            }
172        }
173        unreachable!()
174    }
175    /// Fetch the `Date` field from the email
176    pub fn get_date(&self) -> OrigDate {
177        for field in self.message.fields.fields.iter() {
178            if let Field::OrigDate(ref d) = *field {
179                return d.clone();
180            }
181        }
182        unreachable!()
183    }
184
185    /// Replace the `From` field in the email
186    pub fn set_from<F>(&mut self, from: F) -> Result<(), ParseError>
187        where From: TryFrom<F, Error=ParseError>
188    {
189        let value: From = TryFrom::try_from(from)?;
190        for field in self.message.fields.fields.iter_mut() {
191            if let Field::From(_) = *field {
192                *field = Field::From(value);
193                return Ok(());
194            }
195        }
196        unreachable!()
197    }
198    /// Fetch the `From` field from the email
199    pub fn get_from(&self) -> From {
200        for field in self.message.fields.fields.iter() {
201            if let Field::From(ref f) = *field {
202                return f.clone()
203            }
204        }
205        unreachable!()
206    }
207
208    /// Set or replace the `Sender` field in the email
209    pub fn set_sender<S>(&mut self, sender: S) -> Result<(), ParseError>
210        where Sender: TryFrom<S, Error=ParseError>
211    {
212        let value: Sender = TryFrom::try_from(sender)?;
213        for field in self.message.fields.fields.iter_mut() {
214            if let Field::Sender(_) = *field {
215                *field = Field::Sender(value);
216                return Ok(());
217            }
218        }
219        self.message.fields.fields.push(Field::Sender(value));
220        Ok(())
221    }
222    /// Fetch the `Sender` field from the email
223    pub fn get_sender(&self) -> Option<Sender> {
224        for field in self.message.fields.fields.iter() {
225            if let Field::Sender(ref s) = *field {
226                return Some(s.clone());
227            }
228        }
229        None
230    }
231    /// Remove the `Sender` field from the email
232    pub fn clear_sender(&mut self) {
233        self.message.fields.fields.retain(|field| {
234            if let Field::Sender(_) = *field { false } else { true }
235        });
236    }
237
238    /// Set or replace the `Reply-To` field in the email
239    pub fn set_reply_to<R>(&mut self, reply_to: R) -> Result<(), ParseError>
240        where ReplyTo: TryFrom<R, Error=ParseError>
241    {
242        let value: ReplyTo = TryFrom::try_from(reply_to)?;
243        for field in self.message.fields.fields.iter_mut() {
244            if let Field::ReplyTo(_) = *field {
245                *field = Field::ReplyTo(value);
246                return Ok(());
247            }
248        }
249        self.message.fields.fields.push(Field::ReplyTo(value));
250        Ok(())
251    }
252    /// Fetch the `Reply-To` field from the email
253    pub fn get_reply_to(&self) -> Option<ReplyTo> {
254        for field in self.message.fields.fields.iter() {
255            if let Field::ReplyTo(ref rt) = *field {
256                return Some(rt.clone())
257            }
258        }
259        None
260    }
261    /// Remove the `Reply-To` field from the email
262    pub fn clear_reply_to(&mut self) {
263        self.message.fields.fields.retain(|field| {
264            if let Field::ReplyTo(_) = *field { false } else { true }
265        });
266    }
267
268    /// Set or replace the `To` field in the email
269    pub fn set_to<T>(&mut self, to: T) -> Result<(), ParseError>
270        where To: TryFrom<T, Error=ParseError>
271    {
272        let value: To = TryFrom::try_from(to)?;
273        for field in self.message.fields.fields.iter_mut() {
274            if let Field::To(_) = *field {
275                *field = Field::To(value);
276                return Ok(());
277            }
278        }
279        self.message.fields.fields.push(Field::To(value));
280        Ok(())
281    }
282    /// Fetch the `To` field from the email
283    pub fn get_to(&self) -> Option<To> {
284        for field in self.message.fields.fields.iter() {
285            if let Field::To(ref t) = *field {
286                return Some(t.clone())
287            }
288        }
289        None
290    }
291    /// Remove the `To` field from the email
292    pub fn clear_to(&mut self) {
293        self.message.fields.fields.retain(|field| {
294            if let Field::To(_) = *field { false } else { true }
295        });
296    }
297
298    /// Set or replace the `Cc` field in the email
299    pub fn set_cc<C>(&mut self, cc: C) -> Result<(), ParseError>
300        where Cc: TryFrom<C, Error=ParseError>
301    {
302        let value: Cc = TryFrom::try_from(cc)?;
303        for field in self.message.fields.fields.iter_mut() {
304            if let Field::Cc(_) = *field {
305                *field = Field::Cc(value);
306                return Ok(());
307            }
308        }
309        self.message.fields.fields.push(Field::Cc(value));
310        Ok(())
311    }
312    /// Fetch the `Cc` field from the email
313    pub fn get_cc(&self) -> Option<Cc> {
314        for field in self.message.fields.fields.iter() {
315            if let Field::Cc(ref cc) = *field {
316                return Some(cc.clone())
317            }
318        }
319        None
320    }
321    /// Remove the `Cc` field from the email
322    pub fn clear_cc(&mut self) {
323        self.message.fields.fields.retain(|field| {
324            if let Field::Cc(_) = *field { false } else { true }
325        });
326    }
327
328    /// Set or replace the `Bcc` field in the email
329    pub fn set_bcc<B>(&mut self, bcc: B) -> Result<(), ParseError>
330        where Bcc: TryFrom<B, Error=ParseError>
331    {
332        let value: Bcc = TryFrom::try_from(bcc)?;
333        for field in self.message.fields.fields.iter_mut() {
334            if let Field::Bcc(_) = *field {
335                *field = Field::Bcc(value);
336                return Ok(());
337            }
338        }
339        self.message.fields.fields.push(Field::Bcc(value));
340        Ok(())
341    }
342    /// Fetch the `Bcc` field from the email
343    pub fn get_bcc(&self) -> Option<Bcc> {
344        for field in self.message.fields.fields.iter() {
345            if let Field::Bcc(ref b) = *field {
346                return Some(b.clone())
347            }
348        }
349        None
350    }
351    /// Remove the `Bcc` field from the email
352    pub fn clear_bcc(&mut self) {
353        self.message.fields.fields.retain(|field| {
354            if let Field::Bcc(_) = *field { false } else { true }
355        });
356    }
357
358    /// Set or replace the `Message-ID` field in the email
359    pub fn set_message_id<M>(&mut self, message_id: M) -> Result<(), ParseError>
360        where MessageId: TryFrom<M, Error=ParseError>
361    {
362        let value: MessageId = TryFrom::try_from(message_id)?;
363        for field in self.message.fields.fields.iter_mut() {
364            if let Field::MessageId(_) = *field {
365                *field = Field::MessageId(value);
366                return Ok(());
367            }
368        }
369        self.message.fields.fields.push(Field::MessageId(value));
370        Ok(())
371    }
372    /// Fetch the `Message-ID` field from the email
373    pub fn get_message_id(&self) -> Option<MessageId> {
374        for field in self.message.fields.fields.iter() {
375            if let Field::MessageId(ref m) = *field {
376                return Some(m.clone())
377            }
378        }
379        None
380    }
381    /// Remove the `Message-ID` field from the email
382    pub fn clear_message_id(&mut self) {
383        self.message.fields.fields.retain(|field| {
384            if let Field::MessageId(_) = *field { false } else { true }
385        });
386    }
387
388    /// Set or replace the `In-Reply-To` field in the email
389    pub fn set_in_reply_to<I>(&mut self, in_reply_to: I) -> Result<(), ParseError>
390        where InReplyTo: TryFrom<I, Error=ParseError>
391    {
392        let value: InReplyTo = TryFrom::try_from(in_reply_to)?;
393        for field in self.message.fields.fields.iter_mut() {
394            if let Field::InReplyTo(_) = *field {
395                *field = Field::InReplyTo(value);
396                return Ok(());
397            }
398        }
399        self.message.fields.fields.push(Field::InReplyTo(value));
400        Ok(())
401    }
402    /// Fetch the `In-Reply-To` field from the email
403    pub fn get_in_reply_to(&self) -> Option<InReplyTo> {
404        for field in self.message.fields.fields.iter() {
405            if let Field::InReplyTo(ref x) = *field {
406                return Some(x.clone())
407            }
408        }
409        None
410    }
411    /// Remove the `In-Reply-To` field from the email
412    pub fn clear_in_reply_to(&mut self) {
413        self.message.fields.fields.retain(|field| {
414            if let Field::InReplyTo(_) = *field { false } else { true }
415        });
416    }
417
418    /// Set or replace the `References` field in the email
419    pub fn set_references<R>(&mut self, references: R) -> Result<(), ParseError>
420        where References: TryFrom<R, Error=ParseError>
421    {
422        let value: References = TryFrom::try_from(references)?;
423        for field in self.message.fields.fields.iter_mut() {
424            if let Field::References(_) = *field {
425                *field = Field::References(value);
426                return Ok(());
427            }
428        }
429        self.message.fields.fields.push(Field::References(value));
430        Ok(())
431    }
432    /// Fetch the `References` field from the email
433    pub fn get_references(&self) -> Option<References> {
434        for field in self.message.fields.fields.iter() {
435            if let Field::References(ref x) = *field {
436                return Some(x.clone())
437            }
438        }
439        None
440    }
441    /// Remove the `References` field from the email
442    pub fn clear_references(&mut self) {
443        self.message.fields.fields.retain(|field| {
444            if let Field::References(_) = *field { false } else { true }
445        });
446    }
447
448    /// Set or replace the `Subject` field in the email
449    pub fn set_subject<S>(&mut self, subject: S) -> Result<(), ParseError>
450        where Subject: TryFrom<S, Error=ParseError>
451    {
452        let value: Subject = TryFrom::try_from(subject)?;
453        for field in self.message.fields.fields.iter_mut() {
454            if let Field::Subject(_) = *field {
455                *field = Field::Subject(value);
456                return Ok(());
457            }
458        }
459        self.message.fields.fields.push(Field::Subject(value));
460        Ok(())
461    }
462    /// Fetch the `Subject` field from the email
463    pub fn get_subject(&self) -> Option<Subject> {
464        for field in self.message.fields.fields.iter() {
465            if let Field::Subject(ref x) = *field {
466                return Some(x.clone())
467            }
468        }
469        None
470    }
471    /// Remove the `Subject` field from the email
472    pub fn clear_subject(&mut self) {
473        self.message.fields.fields.retain(|field| {
474            if let Field::Subject(_) = *field { false } else { true }
475        });
476    }
477
478    /// Add a `Comments` field in the email. This may be in addition to
479    /// existing `Comments` fields.
480    pub fn add_comments<C>(&mut self, comments: C) -> Result<(), ParseError>
481        where Comments: TryFrom<C, Error=ParseError>
482    {
483        let value: Comments = TryFrom::try_from(comments)?;
484        self.message.fields.fields.push(Field::Comments(value));
485        Ok(())
486    }
487    /// Fetch all `Comments` fields from the email
488    pub fn get_comments(&self) -> Vec<Comments> {
489        let mut output: Vec<Comments> = Vec::new();
490        for field in self.message.fields.fields.iter() {
491            if let Field::Comments(ref x) = *field {
492                output.push(x.clone());
493            }
494        }
495        output
496    }
497    /// Remove all `Comments` fields from the email
498    pub fn clear_comments(&mut self) {
499        self.message.fields.fields.retain(|field| {
500            if let Field::Comments(_) = *field { false } else { true }
501        });
502    }
503
504    /// Add a `Keywords` field in the email. This may be in addition to existing
505    /// `Keywords` fields.
506    pub fn add_keywords<K>(&mut self, keywords: K) -> Result<(), ParseError>
507        where Keywords: TryFrom<K, Error=ParseError>
508    {
509        let value: Keywords = TryFrom::try_from(keywords)?;
510        self.message.fields.fields.push(Field::Keywords(value));
511        Ok(())
512    }
513    /// Fetch all `Keywords` fields from the email
514    pub fn get_keywords(&self) -> Vec<Keywords> {
515        let mut output: Vec<Keywords> = Vec::new();
516        for field in self.message.fields.fields.iter() {
517            if let Field::Keywords(ref x) = *field {
518                output.push(x.clone());
519            }
520        }
521        output
522    }
523    /// Remove all `Keywords` fields from the email
524    pub fn clear_keywords(&mut self) {
525        self.message.fields.fields.retain(|field| {
526            if let Field::Keywords(_) = *field { false } else { true }
527        });
528    }
529
530    /// Add an optional field to the email. This may be in addition to existing
531    /// optional fields.
532    pub fn add_optional_field<O>(&mut self, optional_field: O) -> Result<(), ParseError>
533        where OptionalField: TryFrom<O, Error=ParseError>
534    {
535        let value: OptionalField = TryFrom::try_from(optional_field)?;
536        self.message.fields.fields.push(Field::OptionalField(value));
537        Ok(())
538    }
539    /// Fetch all optional fields from the email
540    pub fn get_optional_fields(&self) -> Vec<OptionalField> {
541        let mut output: Vec<OptionalField> = Vec::new();
542        for field in self.message.fields.fields.iter() {
543            if let Field::OptionalField(ref x) = *field {
544                output.push(x.clone());
545            }
546        }
547        output
548    }
549    /// Clear all optional fields from the email
550    pub fn clear_optional_fields(&mut self) {
551        self.message.fields.fields.retain(|field| {
552            if let Field::OptionalField(_) = *field {
553                false
554            } else {
555                true
556            }
557        })
558    }
559
560    // TBD: trace
561    // TBD: resent-date
562    // TBD: resent-from
563    // TBD: resent-sender
564    // TBD: resent-to
565    // TBD: resent-cc
566    // TBD: resent-bcc
567    // TBD: resent-msg-id
568
569    /// Set or replace the `Body` in the email
570    pub fn set_body<B>(&mut self, body: B) -> Result<(), ParseError>
571        where Body: TryFrom<B, Error=ParseError>
572    {
573        let value: Body = TryFrom::try_from(body)?;
574        self.message.body = Some(value);
575        Ok(())
576    }
577    /// Fetch the `Body` from the email
578    pub fn get_body(&self) -> Option<Body> {
579        self.message.body.clone()
580    }
581    /// Remove the `Body` from the email, leaving an empty body
582    pub fn clear_body(&mut self) {
583        self.message.body = None;
584    }
585
586    /// Stream the email into a byte vector and return that
587    pub fn as_bytes(&self) -> Vec<u8> {
588        let mut output: Vec<u8> = Vec::new();
589        let _ = self.stream(&mut output); // no IoError ought to occur.
590        output
591    }
592
593    /// Stream the email into a byte vector, convert to a String, and
594    /// return that
595    pub fn as_string(&self) -> String {
596        let mut vec: Vec<u8> = Vec::new();
597        let _ = self.stream(&mut vec); // no IoError ought to occur.
598        unsafe {
599            // rfc5322 formatted emails fall within utf8, so this should not be
600            // able to fail
601            String::from_utf8_unchecked(vec)
602        }
603    }
604
605    /// Create a `lettre::SendableEmail` from this Email.
606    ///
607    /// We require `&mut self` because we temporarily strip off the Bcc line
608    /// when we generate the message, and then we put it back afterwards to
609    /// leave `self` in a functionally unmodified state.
610    #[cfg(feature="lettre")]
611    pub fn as_sendable_email(&mut self) ->
612        Result<::lettre::SendableEmail, &'static str>
613    {
614        use lettre::{SendableEmail, EmailAddress, Envelope};
615        use rfc5322::types::Address;
616
617        let mut rfc_recipients: Vec<Address> = Vec::new();
618        if let Some(to) = self.get_to() {
619            rfc_recipients.extend((to.0).0);
620        }
621        if let Some(cc) = self.get_cc() {
622            rfc_recipients.extend((cc.0).0);
623        }
624        if let Some(bcc) = self.get_bcc() {
625            if let Bcc::AddressList(al) = bcc {
626                rfc_recipients.extend(al.0);
627            }
628        }
629
630        // Remove duplicates
631        rfc_recipients.dedup();
632
633        let rfc_address_to_lettre = |a: Address| -> Result<EmailAddress, &'static str> {
634            let s = format!("{}", a).trim().to_string();
635            EmailAddress::new(s).map_err(|_| "Invalid email to address")
636        };
637        let rfc_from_to_lettre = |f: From| -> Result<EmailAddress, &'static str> {
638            let s = format!("{}", f.0).trim().to_string();
639            EmailAddress::new(s).map_err(|_| "Invalid email from address")
640        };
641
642        // Map to lettre::EmailAddress
643        let mut lettre_recipients: Vec<EmailAddress> = vec![];
644        for address in rfc_recipients.drain(..) {
645            lettre_recipients.push(rfc_address_to_lettre(address)?);
646        }
647
648        let from_addr = rfc_from_to_lettre(self.get_from())?;
649
650        let message_id = match self.get_message_id() {
651            Some(mid) => format!("{}@{}", mid.0.id_left, mid.0.id_right),
652            None => return Err("email has no Message-ID"),
653        };
654
655        // Remove Bcc header before creating body (RFC 5321 section 7.2)
656        let maybe_bcc = self.get_bcc();
657        self.clear_bcc();
658
659        let message = format!("{}", self);
660
661        // Put the Bcc back to restore the caller's argument
662        if let Some(bcc) = maybe_bcc {
663            if let Err(_) = self.set_bcc(bcc) {
664                return Err("Unable to restore the Bcc line");
665            }
666        }
667
668        let envelope = Envelope::new(Some(from_addr), lettre_recipients)
669            .map_err(|_| "Invalid envelope")?;
670        Ok(SendableEmail::new(envelope, message_id, message.as_bytes().to_vec()))
671    }
672}
673
674impl Parsable for Email {
675    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
676        let mut rem = input;
677        match Message::parse(rem).map(|(value, r)| { rem = r; value }) {
678            Ok(message) => Ok((Email { message: message}, rem)),
679            Err(e) => Err(ParseError::Parse("Email", Box::new(e)))
680        }
681    }
682}
683
684impl Streamable for Email {
685    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
686        self.message.stream(w)
687    }
688}
689
690impl fmt::Display for Email {
691    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
692        let bytes = self.as_bytes();
693        unsafe {
694            // rfc5322 formatted emails fall within utf8, so this should not be
695            // able to fail
696            write!(f, "{}", ::std::str::from_utf8_unchecked(&*bytes))
697        }
698    }
699}