feat(all): Start using the failure crate for errors
This commit is contained in:
@@ -28,6 +28,8 @@ hostname = { version = "^0.1", optional = true }
|
|||||||
serde = { version = "^1.0", optional = true }
|
serde = { version = "^1.0", optional = true }
|
||||||
serde_json = { version = "^1.0", optional = true }
|
serde_json = { version = "^1.0", optional = true }
|
||||||
serde_derive = { version = "^1.0", optional = true }
|
serde_derive = { version = "^1.0", optional = true }
|
||||||
|
failure = "^0.1"
|
||||||
|
failure_derive = "^0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "^0.5"
|
env_logger = "^0.5"
|
||||||
|
|||||||
18
lettre/src/error.rs
Normal file
18
lettre/src/error.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use failure;
|
||||||
|
|
||||||
|
/// Error type for email content
|
||||||
|
#[derive(Fail, Debug, Clone, Copy)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Missing from in envelope
|
||||||
|
#[fail(display = "missing source address, invalid envelope")]
|
||||||
|
MissingFrom,
|
||||||
|
/// Missing to in envelope
|
||||||
|
#[fail(display = "missing destination address, invalid envelope")]
|
||||||
|
MissingTo,
|
||||||
|
/// Invalid email
|
||||||
|
#[fail(display = "invalid email address")]
|
||||||
|
InvalidEmailAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Email result type
|
||||||
|
pub type EmailResult<T> = Result<T, failure::Error>;
|
||||||
@@ -1,63 +1,40 @@
|
|||||||
//! Error and result type for file transport
|
//! Error and result type for file transport
|
||||||
|
|
||||||
use self::Error::*;
|
use failure;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::error::Error as StdError;
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
/// An enum of all error kinds.
|
/// An enum of all error kinds.
|
||||||
#[derive(Debug)]
|
#[derive(Fail, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Internal client error
|
/// Internal client error
|
||||||
Client(&'static str),
|
#[fail(display = "Internal client error: {}", error)]
|
||||||
|
Client { error: &'static str },
|
||||||
/// IO error
|
/// IO error
|
||||||
Io(io::Error),
|
#[fail(display = "IO error: {}", error)]
|
||||||
|
Io { error: io::Error },
|
||||||
/// JSON serialization error
|
/// JSON serialization error
|
||||||
JsonSerialization(serde_json::Error),
|
#[fail(display = "JSON serialization error: {}", error)]
|
||||||
}
|
JsonSerialization { error: serde_json::Error },
|
||||||
|
|
||||||
impl Display for Error {
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
|
|
||||||
fmt.write_str(self.description())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdError for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
Client(err) => err,
|
|
||||||
Io(ref err) => err.description(),
|
|
||||||
JsonSerialization(ref err) => err.description(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&StdError> {
|
|
||||||
match *self {
|
|
||||||
Io(ref err) => Some(&*err),
|
|
||||||
JsonSerialization(ref err) => Some(&*err),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(err: io::Error) -> Error {
|
fn from(err: io::Error) -> Error {
|
||||||
Io(err)
|
Error::Io { error: err }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<serde_json::Error> for Error {
|
impl From<serde_json::Error> for Error {
|
||||||
fn from(err: serde_json::Error) -> Error {
|
fn from(err: serde_json::Error) -> Error {
|
||||||
JsonSerialization(err)
|
Error::JsonSerialization { error: err }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&'static str> for Error {
|
impl From<&'static str> for Error {
|
||||||
fn from(string: &'static str) -> Error {
|
fn from(string: &'static str) -> Error {
|
||||||
Client(string)
|
Error::Client { error: string }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SMTP result type
|
/// SMTP result type
|
||||||
pub type FileResult = Result<(), Error>;
|
pub type FileResult = Result<(), failure::Error>;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#![doc(html_root_url = "https://docs.rs/lettre/0.9.0")]
|
#![doc(html_root_url = "https://docs.rs/lettre/0.9.0")]
|
||||||
#![deny(
|
#![deny(
|
||||||
missing_copy_implementations, trivial_casts, trivial_numeric_casts, unsafe_code,
|
missing_copy_implementations, trivial_casts, trivial_numeric_casts, unsafe_code,
|
||||||
unstable_features, unused_import_braces, unused_qualifications
|
unstable_features, unused_import_braces
|
||||||
)]
|
)]
|
||||||
#[cfg(feature = "smtp-transport")]
|
#[cfg(feature = "smtp-transport")]
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
@@ -26,9 +26,13 @@ extern crate serde;
|
|||||||
#[cfg(feature = "serde-impls")]
|
#[cfg(feature = "serde-impls")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
extern crate failure;
|
||||||
#[cfg(feature = "file-transport")]
|
#[cfg(feature = "file-transport")]
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate failure_derive;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
#[cfg(feature = "file-transport")]
|
#[cfg(feature = "file-transport")]
|
||||||
pub mod file;
|
pub mod file;
|
||||||
#[cfg(feature = "sendmail-transport")]
|
#[cfg(feature = "sendmail-transport")]
|
||||||
@@ -37,6 +41,9 @@ pub mod sendmail;
|
|||||||
pub mod smtp;
|
pub mod smtp;
|
||||||
pub mod stub;
|
pub mod stub;
|
||||||
|
|
||||||
|
use error::EmailResult;
|
||||||
|
use error::Error as EmailError;
|
||||||
|
use failure::Error;
|
||||||
#[cfg(feature = "file-transport")]
|
#[cfg(feature = "file-transport")]
|
||||||
pub use file::FileTransport;
|
pub use file::FileTransport;
|
||||||
#[cfg(feature = "sendmail-transport")]
|
#[cfg(feature = "sendmail-transport")]
|
||||||
@@ -45,47 +52,12 @@ pub use sendmail::SendmailTransport;
|
|||||||
pub use smtp::client::net::ClientTlsParameters;
|
pub use smtp::client::net::ClientTlsParameters;
|
||||||
#[cfg(feature = "smtp-transport")]
|
#[cfg(feature = "smtp-transport")]
|
||||||
pub use smtp::{ClientSecurity, SmtpClient, SmtpTransport};
|
pub use smtp::{ClientSecurity, SmtpClient, SmtpTransport};
|
||||||
use std::error::Error as StdError;
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
/// Error type for email content
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum Error {
|
|
||||||
/// Missing from in envelope
|
|
||||||
MissingFrom,
|
|
||||||
/// Missing to in envelope
|
|
||||||
MissingTo,
|
|
||||||
/// Invalid email
|
|
||||||
InvalidEmailAddress,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdError for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
Error::MissingFrom => "missing source address, invalid envelope",
|
|
||||||
Error::MissingTo => "missing destination address, invalid envelope",
|
|
||||||
Error::InvalidEmailAddress => "invalid email address",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&StdError> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Error {
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
|
|
||||||
fmt.write_str(self.description())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Email result type
|
|
||||||
pub type EmailResult<T> = Result<T, Error>;
|
|
||||||
|
|
||||||
/// Email address
|
/// Email address
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
|
||||||
@@ -131,7 +103,7 @@ impl Envelope {
|
|||||||
/// Creates a new envelope, which may fail if `to` is empty.
|
/// Creates a new envelope, which may fail if `to` is empty.
|
||||||
pub fn new(from: Option<EmailAddress>, to: Vec<EmailAddress>) -> EmailResult<Envelope> {
|
pub fn new(from: Option<EmailAddress>, to: Vec<EmailAddress>) -> EmailResult<Envelope> {
|
||||||
if to.is_empty() {
|
if to.is_empty() {
|
||||||
return Err(Error::MissingTo);
|
Err(EmailError::MissingTo)?;
|
||||||
}
|
}
|
||||||
Ok(Envelope {
|
Ok(Envelope {
|
||||||
forward_path: to,
|
forward_path: to,
|
||||||
|
|||||||
@@ -1,52 +1,30 @@
|
|||||||
//! Error and result type for sendmail transport
|
//! Error and result type for sendmail transport
|
||||||
|
|
||||||
use self::Error::*;
|
use failure;
|
||||||
use std::error::Error as StdError;
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
/// An enum of all error kinds.
|
/// An enum of all error kinds.
|
||||||
#[derive(Debug)]
|
#[derive(Fail, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Internal client error
|
/// Internal client error
|
||||||
Client(&'static str),
|
#[fail(display = "Internal client error: {}", error)]
|
||||||
|
Client { error: &'static str },
|
||||||
/// IO error
|
/// IO error
|
||||||
Io(io::Error),
|
#[fail(display = "IO error: {}", error)]
|
||||||
}
|
Io { error: io::Error },
|
||||||
|
|
||||||
impl Display for Error {
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
|
|
||||||
fmt.write_str(self.description())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdError for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
Client(err) => err,
|
|
||||||
Io(ref err) => err.description(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&StdError> {
|
|
||||||
match *self {
|
|
||||||
Io(ref err) => Some(&*err),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(err: io::Error) -> Error {
|
fn from(err: io::Error) -> Error {
|
||||||
Io(err)
|
Error::Io { error: err }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&'static str> for Error {
|
impl From<&'static str> for Error {
|
||||||
fn from(string: &'static str) -> Error {
|
fn from(string: &'static str) -> Error {
|
||||||
Client(string)
|
Error::Client { error: string }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// sendmail result type
|
/// sendmail result type
|
||||||
pub type SendmailResult = Result<(), Error>;
|
pub type SendmailResult = Result<(), failure::Error>;
|
||||||
|
|||||||
@@ -58,26 +58,23 @@ impl<'a> Transport<'a> for SendmailTransport {
|
|||||||
let mut message_content = String::new();
|
let mut message_content = String::new();
|
||||||
let _ = email.message().read_to_string(&mut message_content);
|
let _ = email.message().read_to_string(&mut message_content);
|
||||||
|
|
||||||
match process
|
process
|
||||||
.stdin
|
.stdin
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write_all(message_content.as_bytes())
|
.write_all(message_content.as_bytes())?;
|
||||||
{
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(error) => return Err(From::from(error)),
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Wrote {} message to stdin", message_id);
|
info!("Wrote {} message to stdin", message_id);
|
||||||
|
|
||||||
if let Ok(output) = process.wait_with_output() {
|
let output = process.wait_with_output()?;
|
||||||
if output.status.success() {
|
|
||||||
Ok(())
|
if output.status.success() {
|
||||||
} else {
|
Ok(())
|
||||||
Err(From::from("The message could not be sent"))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(From::from("The sendmail process stopped"))
|
// TODO display stderr
|
||||||
|
Err(error::Error::Client {
|
||||||
|
error: "The message could not be sent",
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,3 +29,5 @@ time = "^0.1"
|
|||||||
uuid = { version = "^0.6", features = ["v4"] }
|
uuid = { version = "^0.6", features = ["v4"] }
|
||||||
lettre = { version = "^0.9", path = "../lettre", default-features = false }
|
lettre = { version = "^0.9", path = "../lettre", default-features = false }
|
||||||
base64 = "^0.9"
|
base64 = "^0.9"
|
||||||
|
failure = "^0.1"
|
||||||
|
failure_derive = "^0.1"
|
||||||
@@ -1,47 +1,36 @@
|
|||||||
//! Error and result type for emails
|
//! Error and result type for emails
|
||||||
|
|
||||||
use self::Error::*;
|
use lettre;
|
||||||
use std::error::Error as StdError;
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use lettre;
|
|
||||||
|
|
||||||
/// An enum of all error kinds.
|
/// An enum of all error kinds.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Fail)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Envelope error
|
/// Envelope error
|
||||||
Email(lettre::Error),
|
#[fail(display = "lettre error: {}", error)]
|
||||||
|
Envelope {
|
||||||
|
/// inner error
|
||||||
|
error: lettre::error::Error,
|
||||||
|
},
|
||||||
/// Unparseable filename for attachment
|
/// Unparseable filename for attachment
|
||||||
|
#[fail(display = "the attachment filename could not be parsed")]
|
||||||
CannotParseFilename,
|
CannotParseFilename,
|
||||||
/// IO error
|
/// IO error
|
||||||
Io(io::Error),
|
#[fail(display = "IO error: {}", error)]
|
||||||
}
|
Io {
|
||||||
|
/// inner error
|
||||||
impl Display for Error {
|
error: io::Error,
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
|
},
|
||||||
fmt.write_str(self.description())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdError for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
Email(ref err) => err.description(),
|
|
||||||
CannotParseFilename => "the attachment filename could not be parsed",
|
|
||||||
Io(ref err) => err.description(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(err: io::Error) -> Error {
|
fn from(err: io::Error) -> Error {
|
||||||
Io(err)
|
Error::Io { error: err }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<lettre::Error> for Error {
|
impl From<lettre::error::Error> for Error {
|
||||||
fn from(err: lettre::Error) -> Error {
|
fn from(err: lettre::error::Error) -> Error {
|
||||||
Email(err)
|
Error::Envelope { error: err }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
#![doc(html_root_url = "https://docs.rs/lettre_email/0.9.0")]
|
#![doc(html_root_url = "https://docs.rs/lettre_email/0.9.0")]
|
||||||
#![deny(
|
#![deny(
|
||||||
missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
|
missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
|
||||||
trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
|
trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces
|
||||||
unused_qualifications
|
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
extern crate failure;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate failure_derive;
|
||||||
|
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
extern crate email as email_format;
|
extern crate email as email_format;
|
||||||
extern crate lettre;
|
extern crate lettre;
|
||||||
@@ -18,8 +21,9 @@ extern crate uuid;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub use email_format::{Address, Header, Mailbox, MimeMessage, MimeMultipartType};
|
pub use email_format::{Address, Header, Mailbox, MimeMessage, MimeMultipartType};
|
||||||
use error::Error;
|
use error::Error as EmailError;
|
||||||
use lettre::{EmailAddress, Envelope, Error as EmailError, SendableEmail};
|
use failure::Error;
|
||||||
|
use lettre::{error::Error as LettreError, EmailAddress, Envelope, SendableEmail};
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -231,7 +235,7 @@ impl EmailBuilder {
|
|||||||
fs::read(path)?.as_slice(),
|
fs::read(path)?.as_slice(),
|
||||||
filename.unwrap_or(path.file_name()
|
filename.unwrap_or(path.file_name()
|
||||||
.and_then(|x| x.to_str())
|
.and_then(|x| x.to_str())
|
||||||
.ok_or(Error::CannotParseFilename)?),
|
.ok_or(EmailError::CannotParseFilename)?),
|
||||||
content_type,
|
content_type,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -369,26 +373,30 @@ impl EmailBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let from = Some(EmailAddress::from_str(&match self.sender {
|
let from = Some(EmailAddress::from_str(&match self.sender {
|
||||||
Some(x) => x.address.clone(), // if we have a sender_header, use it
|
Some(x) => Ok(x.address.clone()), // if we have a sender_header, use it
|
||||||
None => {
|
None => {
|
||||||
// use a from header
|
// use a from header
|
||||||
debug_assert!(self.from.len() <= 1); // else we'd have sender_header
|
debug_assert!(self.from.len() <= 1); // else we'd have sender_header
|
||||||
match self.from.first() {
|
match self.from.first() {
|
||||||
Some(a) => match *a {
|
Some(a) => match *a {
|
||||||
// if we have a from header
|
// if we have a from header
|
||||||
Address::Mailbox(ref mailbox) => mailbox.address.clone(), // use it
|
Address::Mailbox(ref mailbox) => Ok(mailbox.address.clone()), // use it
|
||||||
Address::Group(_, ref mailbox_list) => match mailbox_list.first() {
|
Address::Group(_, ref mailbox_list) => match mailbox_list.first() {
|
||||||
// if it's an author group, use the first author
|
// if it's an author group, use the first author
|
||||||
Some(mailbox) => mailbox.address.clone(),
|
Some(mailbox) => Ok(mailbox.address.clone()),
|
||||||
// for an empty author group (the rarest of the rare cases)
|
// for an empty author group (the rarest of the rare cases)
|
||||||
None => return Err(Error::Email(EmailError::MissingFrom)), // empty envelope sender
|
None => Err(EmailError::Envelope {
|
||||||
|
error: LettreError::MissingFrom,
|
||||||
|
}), // empty envelope sender
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// if we don't have a from header
|
// if we don't have a from header
|
||||||
None => return Err(Error::Email(EmailError::MissingFrom)), // empty envelope sender
|
None => Err(EmailError::Envelope {
|
||||||
|
error: LettreError::MissingFrom,
|
||||||
|
}), // empty envelope sender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})?);
|
}?)?);
|
||||||
Envelope::new(from, to)?
|
Envelope::new(from, to)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -402,7 +410,9 @@ impl EmailBuilder {
|
|||||||
self.message = self.message
|
self.message = self.message
|
||||||
.header(Header::new_with_value("From".into(), self.from).unwrap());
|
.header(Header::new_with_value("From".into(), self.from).unwrap());
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::Email(EmailError::MissingFrom));
|
Err(EmailError::Envelope {
|
||||||
|
error: LettreError::MissingFrom,
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
if !self.cc.is_empty() {
|
if !self.cc.is_empty() {
|
||||||
self.message = self.message
|
self.message = self.message
|
||||||
|
|||||||
Reference in New Issue
Block a user