feat(transport): Make Transport result type an actual Result (fixes #405)
This commit is contained in:
13
src/lib.rs
13
src/lib.rs
@@ -45,6 +45,8 @@ pub use crate::transport::smtp::{SmtpTransport, Tls};
|
||||
pub use crate::transport::stub::StubTransport;
|
||||
#[cfg(feature = "builder")]
|
||||
use std::convert::TryFrom;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
|
||||
/// Simple email envelope representation
|
||||
///
|
||||
@@ -117,17 +119,18 @@ impl TryFrom<&Headers> for Envelope {
|
||||
}
|
||||
|
||||
/// Transport method for emails
|
||||
pub trait Transport<'a> {
|
||||
/// Result type for the transport
|
||||
type Result;
|
||||
pub trait Transport {
|
||||
/// Result types for the transport
|
||||
type Ok: fmt::Debug;
|
||||
type Error: StdError;
|
||||
|
||||
/// Sends the email
|
||||
fn send(&self, message: &Message) -> Self::Result {
|
||||
fn send(&self, message: &Message) -> Result<Self::Ok, Self::Error> {
|
||||
let raw = message.formatted();
|
||||
self.send_raw(message.envelope(), &raw)
|
||||
}
|
||||
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result;
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -55,8 +55,3 @@ impl From<&'static str> for Error {
|
||||
Error::Client(string)
|
||||
}
|
||||
}
|
||||
|
||||
type Id = String;
|
||||
|
||||
/// SMTP result type
|
||||
pub type FileResult = Result<Id, Error>;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
//! TODO
|
||||
//! ```
|
||||
|
||||
use crate::{transport::file::error::FileResult, Envelope, Transport};
|
||||
use crate::{transport::file::error::Error, Envelope, Transport};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::prelude::*,
|
||||
@@ -46,6 +46,8 @@ use uuid::Uuid;
|
||||
|
||||
pub mod error;
|
||||
|
||||
type Id = String;
|
||||
|
||||
/// Writes the content and the envelope information to a file
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
@@ -70,10 +72,11 @@ struct SerializableEmail<'a> {
|
||||
message: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a> Transport<'a> for FileTransport {
|
||||
type Result = FileResult;
|
||||
impl Transport for FileTransport {
|
||||
type Ok = Id;
|
||||
type Error = Error;
|
||||
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result {
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
let email_id = Uuid::new_v4();
|
||||
|
||||
let mut file = self.path.clone();
|
||||
|
||||
@@ -50,6 +50,3 @@ impl From<FromUtf8Error> for Error {
|
||||
Utf8Parsing(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// sendmail result type
|
||||
pub type SendmailResult = Result<(), Error>;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
use crate::{transport::sendmail::error::SendmailResult, Envelope, Transport};
|
||||
use crate::{transport::sendmail::error::Error, Envelope, Transport};
|
||||
use std::{
|
||||
convert::AsRef,
|
||||
io::prelude::*,
|
||||
@@ -55,10 +55,11 @@ impl SendmailTransport {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Transport<'a> for SendmailTransport {
|
||||
type Result = SendmailResult;
|
||||
impl Transport for SendmailTransport {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result {
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
// Spawn the sendmail command
|
||||
let mut process = Command::new(&self.command)
|
||||
.arg("-i")
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
authentication::{Credentials, Mechanism},
|
||||
client::net::{NetworkStream, TlsParameters},
|
||||
commands::*,
|
||||
error::{Error, SmtpResult},
|
||||
error::Error,
|
||||
extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo},
|
||||
response::Response,
|
||||
},
|
||||
@@ -140,7 +140,7 @@ impl SmtpConnection {
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub fn send(&mut self, envelope: &Envelope, email: &[u8]) -> SmtpResult {
|
||||
pub fn send(&mut self, envelope: &Envelope, email: &[u8]) -> Result<Response, Error> {
|
||||
// Mail
|
||||
let mut mail_options = vec![];
|
||||
|
||||
@@ -210,7 +210,7 @@ impl SmtpConnection {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn quit(&mut self) -> SmtpResult {
|
||||
pub fn quit(&mut self) -> Result<Response, Error> {
|
||||
Ok(try_smtp!(self.command(Quit), self))
|
||||
}
|
||||
|
||||
@@ -244,7 +244,11 @@ impl SmtpConnection {
|
||||
}
|
||||
|
||||
/// Sends an AUTH command with the given mechanism, and handles challenge if needed
|
||||
pub fn auth(&mut self, mechanisms: &[Mechanism], credentials: &Credentials) -> SmtpResult {
|
||||
pub fn auth(
|
||||
&mut self,
|
||||
mechanisms: &[Mechanism],
|
||||
credentials: &Credentials,
|
||||
) -> Result<Response, Error> {
|
||||
let mechanism = match self.server_info.get_auth_mechanism(mechanisms) {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
@@ -278,7 +282,7 @@ impl SmtpConnection {
|
||||
}
|
||||
|
||||
/// Sends the message content
|
||||
pub fn message(&mut self, message: &[u8]) -> SmtpResult {
|
||||
pub fn message(&mut self, message: &[u8]) -> Result<Response, Error> {
|
||||
let mut out_buf: Vec<u8> = vec![];
|
||||
let mut codec = ClientCodec::new();
|
||||
codec.encode(message, &mut out_buf)?;
|
||||
@@ -288,7 +292,7 @@ impl SmtpConnection {
|
||||
}
|
||||
|
||||
/// Sends an SMTP command
|
||||
pub fn command<C: Display>(&mut self, command: C) -> SmtpResult {
|
||||
pub fn command<C: Display>(&mut self, command: C) -> Result<Response, Error> {
|
||||
self.write(command.to_string().as_bytes())?;
|
||||
self.read_response()
|
||||
}
|
||||
@@ -307,7 +311,7 @@ impl SmtpConnection {
|
||||
}
|
||||
|
||||
/// Gets the SMTP response
|
||||
pub fn read_response(&mut self) -> SmtpResult {
|
||||
pub fn read_response(&mut self) -> Result<Response, Error> {
|
||||
let mut raw_response = String::new();
|
||||
let mut response = raw_response.parse::<Response>();
|
||||
|
||||
|
||||
@@ -152,6 +152,3 @@ impl From<&'static str> for Error {
|
||||
Client(string)
|
||||
}
|
||||
}
|
||||
|
||||
/// SMTP result type
|
||||
pub type SmtpResult = Result<Response, Error>;
|
||||
|
||||
@@ -182,8 +182,9 @@ use crate::{
|
||||
transport::smtp::{
|
||||
authentication::{Credentials, Mechanism, DEFAULT_MECHANISMS},
|
||||
client::SmtpConnection,
|
||||
error::{Error, SmtpResult},
|
||||
error::Error,
|
||||
extension::ClientId,
|
||||
response::Response,
|
||||
},
|
||||
Envelope, Transport,
|
||||
};
|
||||
@@ -419,11 +420,12 @@ impl SmtpTransport {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Transport<'a> for SmtpTransport {
|
||||
type Result = SmtpResult;
|
||||
impl Transport for SmtpTransport {
|
||||
type Ok = Response;
|
||||
type Error = Error;
|
||||
|
||||
/// Sends an email
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result {
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
#[cfg(feature = "r2d2")]
|
||||
let mut conn: Box<dyn DerefMut<Target = SmtpConnection>> = match self.pool {
|
||||
Some(ref p) => Box::new(p.get()?),
|
||||
|
||||
@@ -17,38 +17,60 @@
|
||||
//! .body("Be happy!")
|
||||
//! .unwrap();
|
||||
//!
|
||||
//! let mut sender = StubTransport::new_positive();
|
||||
//! let mut sender = StubTransport::new_ok();
|
||||
//! let result = sender.send(&email);
|
||||
//! assert!(result.is_ok());
|
||||
//! ```
|
||||
|
||||
use crate::{Envelope, Transport};
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Error;
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "stub error")
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {
|
||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// This transport logs the message envelope and returns the given response
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct StubTransport {
|
||||
response: StubResult,
|
||||
response: Result<(), Error>,
|
||||
}
|
||||
|
||||
impl StubTransport {
|
||||
/// Creates a new transport that always returns the given response
|
||||
pub fn new(response: StubResult) -> StubTransport {
|
||||
/// Creates aResult new transport that always returns the given response
|
||||
pub fn new(response: Result<(), Error>) -> StubTransport {
|
||||
StubTransport { response }
|
||||
}
|
||||
|
||||
/// Creates a new transport that always returns a success response
|
||||
pub fn new_positive() -> StubTransport {
|
||||
pub fn new_ok() -> StubTransport {
|
||||
StubTransport { response: Ok(()) }
|
||||
}
|
||||
|
||||
/// Creates a new transport that always returns an error
|
||||
pub fn new_error() -> StubTransport {
|
||||
StubTransport {
|
||||
response: Err(Error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SMTP result type
|
||||
pub type StubResult = Result<(), ()>;
|
||||
impl Transport for StubTransport {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
impl<'a> Transport<'a> for StubTransport {
|
||||
type Result = StubResult;
|
||||
|
||||
fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Self::Result {
|
||||
fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
self.response
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ use lettre::{transport::stub::StubTransport, Message, Transport};
|
||||
|
||||
#[test]
|
||||
fn stub_transport() {
|
||||
let sender_ok = StubTransport::new_positive();
|
||||
let sender_ko = StubTransport::new(Err(()));
|
||||
let sender_ok = StubTransport::new_ok();
|
||||
let sender_ko = StubTransport::new_error();
|
||||
let email = Message::builder()
|
||||
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
|
||||
|
||||
Reference in New Issue
Block a user