Merge pull request #422 from amousset/sender

fix(builder): Fail if required headers are missing (fixes #95)
This commit is contained in:
Alexis Mousset
2020-05-06 20:41:02 +02:00
committed by GitHub
3 changed files with 57 additions and 24 deletions

View File

@@ -25,12 +25,11 @@ pub mod error;
pub mod message;
pub mod transport;
pub use crate::address::Address;
use crate::error::Error;
#[cfg(feature = "builder")]
pub use crate::message::{
header::{self, Headers},
EmailFormat, Mailboxes, Message,
EmailFormat, Mailbox, Mailboxes, Message,
};
#[cfg(feature = "file-transport")]
pub use crate::transport::file::FileTransport;
@@ -42,11 +41,10 @@ pub use crate::transport::smtp::client::net::TlsParameters;
pub use crate::transport::smtp::r2d2::SmtpConnectionManager;
#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::{SmtpTransport, Tls};
pub use crate::transport::stub::StubTransport;
pub use crate::{address::Address, transport::stub::StubTransport};
#[cfg(feature = "builder")]
use std::convert::TryFrom;
use std::error::Error as StdError;
use std::fmt;
use std::{error::Error as StdError, fmt};
/// Simple email envelope representation
///
@@ -92,9 +90,15 @@ impl TryFrom<&Headers> for Envelope {
let from = match headers.get::<header::Sender>() {
// If there is a Sender, use it
Some(header::Sender(a)) => Some(a.email.clone()),
// ... else use the first From address
// ... else try From
None => match headers.get::<header::From>() {
Some(header::From(ref a)) => Some(a.iter().next().unwrap().email.clone()),
Some(header::From(a)) => {
let from: Vec<Mailbox> = a.clone().into();
if from.len() > 1 {
return Err(Error::TooManyFrom);
}
Some(from[0].email.clone())
}
None => None,
},
};

View File

@@ -364,25 +364,32 @@ impl MessageBuilder {
self
}
fn insert_missing_headers(self) -> Self {
let mut new = self;
// Insert Date if missing
new = if new.headers.get::<header::Date>().is_none() {
new.date_now()
} else {
new
};
// TODO insert sender if needed?
new
}
// TODO: High-level methods for attachments and embedded files
/// Create message from body
fn build(self, body: Body) -> Result<Message, EmailError> {
let res = self.insert_missing_headers();
// Check for missing required headers
// https://tools.ietf.org/html/rfc5322#section-3.6
// Insert Date if missing
let res = if self.headers.get::<header::Date>().is_none() {
self.date_now()
} else {
self
};
// Fail is missing correct originator (Sender or From)
match res.headers.get::<header::From>() {
Some(header::From(f)) => {
let from: Vec<Mailbox> = f.clone().into();
if from.len() > 1 && res.headers.get::<header::Sender>().is_none() {
return Err(EmailError::TooManyFrom);
}
}
None => {
return Err(EmailError::MissingFrom);
}
}
let envelope = match res.envelope {
Some(e) => e,
@@ -485,6 +492,29 @@ impl Default for MessageBuilder {
mod test {
use crate::message::{header, mailbox::Mailbox, Message};
#[test]
fn email_missing_originator() {
assert!(Message::builder().body("Happy new year!").is_err());
}
#[test]
fn email_miminal_message() {
assert!(Message::builder()
.from("NoBody <nobody@domain.tld>".parse().unwrap())
.to("NoBody <nobody@domain.tld>".parse().unwrap())
.body("Happy new year!")
.is_ok());
}
#[test]
fn email_missing_sender() {
assert!(Message::builder()
.from("NoBody <nobody@domain.tld>".parse().unwrap())
.from("AnyBody <anybody@domain.tld>".parse().unwrap())
.body("Happy new year!")
.is_err());
}
#[test]
fn email_message() {
let date = "Tue, 15 Nov 1994 08:12:31 GMT".parse().unwrap();

View File

@@ -23,8 +23,7 @@
//! ```
use crate::{Envelope, Transport};
use std::error::Error as StdError;
use std::fmt;
use std::{error::Error as StdError, fmt};
#[derive(Debug, Copy, Clone)]
pub struct Error;