feat(all): Improve sendmail transport error handling
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
use self::Error::*;
|
||||
use std::io;
|
||||
use std::string::FromUtf8Error;
|
||||
use std::{
|
||||
error::Error as StdError,
|
||||
fmt::{self, Display, Formatter},
|
||||
@@ -11,7 +12,9 @@ use std::{
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Internal client error
|
||||
Client(&'static str),
|
||||
Client(String),
|
||||
/// Error parsing UTF8in response
|
||||
Utf8Parsing(FromUtf8Error),
|
||||
/// IO error
|
||||
Io(io::Error),
|
||||
}
|
||||
@@ -25,7 +28,8 @@ impl Display for Error {
|
||||
impl StdError for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Client(err) => err,
|
||||
Client(ref err) => err,
|
||||
Utf8Parsing(ref err) => err.description(),
|
||||
Io(ref err) => err.description(),
|
||||
}
|
||||
}
|
||||
@@ -33,6 +37,7 @@ impl StdError for Error {
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
match *self {
|
||||
Io(ref err) => Some(&*err),
|
||||
Utf8Parsing(ref err) => Some(&*err),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -44,9 +49,9 @@ impl From<io::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Error {
|
||||
fn from(string: &'static str) -> Error {
|
||||
Error::Client(string)
|
||||
impl From<FromUtf8Error> for Error {
|
||||
fn from(err: FromUtf8Error) -> Error {
|
||||
Utf8Parsing(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,8 +70,7 @@ impl<'a> Transport<'a> for SendmailTransport {
|
||||
if output.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
// TODO display stderr
|
||||
Err(error::Error::Client("The message could not be sent"))?
|
||||
Err(error::Error::Client(String::from_utf8(output.stderr)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ pub const DEFAULT_ENCRYPTED_MECHANISMS: &[Mechanism] = &[Mechanism::Plain, Mecha
|
||||
/// Accepted authentication mechanisms on an unencrypted connection
|
||||
pub const DEFAULT_UNENCRYPTED_MECHANISMS: &[Mechanism] = &[];
|
||||
|
||||
/// Convertable to user credentials
|
||||
/// Convertible to user credentials
|
||||
pub trait IntoCredentials {
|
||||
/// Converts to a `Credentials` struct
|
||||
fn into_credentials(self) -> Credentials;
|
||||
|
||||
@@ -123,22 +123,19 @@ impl<S: Connector + Write + Read + Timeout + Debug> InnerClient<S> {
|
||||
|
||||
/// Tells if the underlying stream is currently encrypted
|
||||
pub fn is_encrypted(&self) -> bool {
|
||||
match self.stream {
|
||||
Some(ref stream) => stream.get_ref().is_encrypted(),
|
||||
None => false,
|
||||
}
|
||||
self.stream
|
||||
.as_ref()
|
||||
.map(|s| s.get_ref().is_encrypted())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Set timeout
|
||||
pub fn set_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
|
||||
match self.stream {
|
||||
Some(ref mut stream) => {
|
||||
stream.get_mut().set_read_timeout(duration)?;
|
||||
stream.get_mut().set_write_timeout(duration)?;
|
||||
Ok(())
|
||||
}
|
||||
None => Ok(()),
|
||||
if let Some(ref mut stream) = self.stream {
|
||||
stream.get_mut().set_read_timeout(duration)?;
|
||||
stream.get_mut().set_write_timeout(duration)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Connects to the configured server
|
||||
|
||||
@@ -92,8 +92,11 @@ impl Write for NetworkStream {
|
||||
/// A trait for the concept of opening a stream
|
||||
pub trait Connector: Sized {
|
||||
/// Opens a connection to the given IP socket
|
||||
fn connect(addr: &SocketAddr, timeout: Option<Duration>, tls_parameters: Option<&ClientTlsParameters>)
|
||||
-> io::Result<Self>;
|
||||
fn connect(
|
||||
addr: &SocketAddr,
|
||||
timeout: Option<Duration>,
|
||||
tls_parameters: Option<&ClientTlsParameters>,
|
||||
) -> io::Result<Self>;
|
||||
/// Upgrades to TLS connection
|
||||
fn upgrade_tls(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()>;
|
||||
/// Is the NetworkStream encrypted
|
||||
|
||||
@@ -174,7 +174,7 @@ impl Response {
|
||||
/// Returns only the first word of the message if possible
|
||||
pub fn first_word(&self) -> Option<&str> {
|
||||
self.message
|
||||
.get(0)
|
||||
.first()
|
||||
.and_then(|line| line.split_whitespace().next())
|
||||
}
|
||||
|
||||
|
||||
@@ -297,10 +297,7 @@ impl EmailBuilder {
|
||||
pub fn text<S: Into<String>>(self, body: S) -> EmailBuilder {
|
||||
let text = PartBuilder::new()
|
||||
.body(body)
|
||||
.header((
|
||||
"Content-Type",
|
||||
mime::TEXT_PLAIN_UTF_8.to_string(),
|
||||
))
|
||||
.header(("Content-Type", mime::TEXT_PLAIN_UTF_8.to_string()))
|
||||
.build();
|
||||
self.child(text)
|
||||
}
|
||||
@@ -309,10 +306,7 @@ impl EmailBuilder {
|
||||
pub fn html<S: Into<String>>(self, body: S) -> EmailBuilder {
|
||||
let html = PartBuilder::new()
|
||||
.body(body)
|
||||
.header((
|
||||
"Content-Type",
|
||||
mime::TEXT_HTML_UTF_8.to_string(),
|
||||
))
|
||||
.header(("Content-Type", mime::TEXT_HTML_UTF_8.to_string()))
|
||||
.build();
|
||||
self.child(html)
|
||||
}
|
||||
@@ -325,18 +319,12 @@ impl EmailBuilder {
|
||||
) -> EmailBuilder {
|
||||
let text = PartBuilder::new()
|
||||
.body(body_text)
|
||||
.header((
|
||||
"Content-Type",
|
||||
mime::TEXT_PLAIN_UTF_8.to_string(),
|
||||
))
|
||||
.header(("Content-Type", mime::TEXT_PLAIN_UTF_8.to_string()))
|
||||
.build();
|
||||
|
||||
let html = PartBuilder::new()
|
||||
.body(body_html)
|
||||
.header((
|
||||
"Content-Type",
|
||||
mime::TEXT_HTML_UTF_8.to_string(),
|
||||
))
|
||||
.header(("Content-Type", mime::TEXT_HTML_UTF_8.to_string()))
|
||||
.build();
|
||||
|
||||
let alternate = PartBuilder::new()
|
||||
|
||||
Reference in New Issue
Block a user