feat(transport): Add an Error and Result type for each transport
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
//! Error and result type for emails
|
||||
|
||||
|
||||
use self::Error::*;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use self::Error::*;
|
||||
|
||||
/// An enum of all error kinds.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//! Simple email representation
|
||||
pub mod error;
|
||||
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use email::error::Error;
|
||||
|
||||
use email_format::{Header, Mailbox, MimeMessage, MimeMultipartType};
|
||||
use mime::Mime;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use time::{Tm, now};
|
||||
use uuid::Uuid;
|
||||
use email::error::Error;
|
||||
|
||||
/// Converts an address or an address with an alias to a `Header`
|
||||
pub trait ToHeader {
|
||||
@@ -640,12 +640,12 @@ impl SendableEmail for Email {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use time::now;
|
||||
|
||||
use uuid::Uuid;
|
||||
use email_format::{Header, MimeMessage};
|
||||
|
||||
use super::{Email, EmailBuilder, Envelope, SendableEmail};
|
||||
use time::now;
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
#[test]
|
||||
fn test_email_display() {
|
||||
|
||||
54
src/transport/file/error.rs
Normal file
54
src/transport/file/error.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
//! Error and result type for file transport
|
||||
|
||||
|
||||
use self::Error::*;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io;
|
||||
|
||||
/// An enum of all error kinds.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Internal client error
|
||||
Client(&'static str),
|
||||
/// IO error
|
||||
Io(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(_) => "an unknown error occured",
|
||||
Io(_) => "an I/O error occured",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
match *self {
|
||||
Io(ref err) => Some(&*err as &StdError),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Error {
|
||||
Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Error {
|
||||
fn from(string: &'static str) -> Error {
|
||||
Client(string)
|
||||
}
|
||||
}
|
||||
|
||||
/// SMTP result type
|
||||
pub type FileResult = Result<(), Error>;
|
||||
@@ -1,15 +1,15 @@
|
||||
//! This transport creates a file for each email, containing the envelope information and the email
|
||||
//! itself.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io::prelude::*;
|
||||
use email::SendableEmail;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use transport::EmailTransport;
|
||||
use transport::error::EmailResult;
|
||||
use transport::smtp::response::Response;
|
||||
use transport::smtp::response::{Category, Code, Severity};
|
||||
use email::SendableEmail;
|
||||
use transport::file::error::FileResult;
|
||||
|
||||
pub mod error;
|
||||
|
||||
/// Writes the content and the envelope information to a file
|
||||
pub struct FileEmailTransport {
|
||||
@@ -25,8 +25,8 @@ impl FileEmailTransport {
|
||||
}
|
||||
}
|
||||
|
||||
impl EmailTransport for FileEmailTransport {
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult {
|
||||
impl EmailTransport<FileResult> for FileEmailTransport {
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> FileResult {
|
||||
let mut file = self.path.clone();
|
||||
file.push(format!("{}.txt", email.message_id()));
|
||||
|
||||
@@ -42,9 +42,7 @@ impl EmailTransport for FileEmailTransport {
|
||||
|
||||
info!("{} status=<written>", log_line);
|
||||
|
||||
Ok(Response::new(Code::new(Severity::PositiveCompletion, Category::MailSystem, 0),
|
||||
vec![format!("Ok: email written to {}",
|
||||
file.to_str().unwrap_or("non-UTF-8 path"))]))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
//! Represents an Email transport
|
||||
pub mod smtp;
|
||||
pub mod error;
|
||||
pub mod stub;
|
||||
pub mod file;
|
||||
|
||||
use transport::error::EmailResult;
|
||||
use email::SendableEmail;
|
||||
|
||||
/// Transport method for emails
|
||||
pub trait EmailTransport {
|
||||
pub trait EmailTransport<U> {
|
||||
/// Sends the email
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult;
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> U;
|
||||
/// Close the transport explicitly
|
||||
fn close(&mut self);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
//! Provides authentication mechanisms
|
||||
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use crypto::hmac::Hmac;
|
||||
use crypto::mac::Mac;
|
||||
use crypto::md5::Md5;
|
||||
|
||||
use rustc_serialize::base64::{self, FromBase64, ToBase64};
|
||||
use rustc_serialize::hex::ToHex;
|
||||
use crypto::hmac::Hmac;
|
||||
use crypto::md5::Md5;
|
||||
use crypto::mac::Mac;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use transport::smtp::NUL;
|
||||
use transport::error::Error;
|
||||
use transport::smtp::error::Error;
|
||||
|
||||
/// Represents authentication mechanisms
|
||||
#[derive(PartialEq,Eq,Copy,Clone,Hash,Debug)]
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
//! SMTP client
|
||||
|
||||
use std::string::String;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::io;
|
||||
use std::io::{BufRead, Read, Write};
|
||||
use std::fmt::Debug;
|
||||
|
||||
use bufstream::BufStream;
|
||||
use openssl::ssl::SslContext;
|
||||
|
||||
use transport::error::{EmailResult, Error};
|
||||
use transport::smtp::response::ResponseParser;
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::io::{BufRead, Read, Write};
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::string::String;
|
||||
use transport::smtp::{CRLF, MESSAGE_ENDING};
|
||||
use transport::smtp::authentication::Mechanism;
|
||||
use transport::smtp::client::net::{Connector, NetworkStream};
|
||||
use transport::smtp::{CRLF, MESSAGE_ENDING};
|
||||
|
||||
use transport::smtp::error::{SmtpResult, Error};
|
||||
use transport::smtp::response::ResponseParser;
|
||||
|
||||
pub mod net;
|
||||
|
||||
@@ -98,7 +98,7 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
|
||||
pub fn connect<A: ToSocketAddrs>(&mut self,
|
||||
addr: &A,
|
||||
ssl_context: Option<&SslContext>)
|
||||
-> EmailResult {
|
||||
-> SmtpResult {
|
||||
// Connect should not be called when the client is already connected
|
||||
if self.stream.is_some() {
|
||||
return_err!("The connection is already established", self);
|
||||
@@ -125,17 +125,17 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
|
||||
}
|
||||
|
||||
/// Sends an SMTP command
|
||||
pub fn command(&mut self, command: &str) -> EmailResult {
|
||||
pub fn command(&mut self, command: &str) -> SmtpResult {
|
||||
self.send_server(command, CRLF)
|
||||
}
|
||||
|
||||
/// Sends a EHLO command
|
||||
pub fn ehlo(&mut self, hostname: &str) -> EmailResult {
|
||||
pub fn ehlo(&mut self, hostname: &str) -> SmtpResult {
|
||||
self.command(&format!("EHLO {}", hostname))
|
||||
}
|
||||
|
||||
/// Sends a MAIL command
|
||||
pub fn mail(&mut self, address: &str, options: Option<&str>) -> EmailResult {
|
||||
pub fn mail(&mut self, address: &str, options: Option<&str>) -> SmtpResult {
|
||||
match options {
|
||||
Some(ref options) => self.command(&format!("MAIL FROM:<{}> {}", address, options)),
|
||||
None => self.command(&format!("MAIL FROM:<{}>", address)),
|
||||
@@ -143,27 +143,27 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
|
||||
}
|
||||
|
||||
/// Sends a RCPT command
|
||||
pub fn rcpt(&mut self, address: &str) -> EmailResult {
|
||||
pub fn rcpt(&mut self, address: &str) -> SmtpResult {
|
||||
self.command(&format!("RCPT TO:<{}>", address))
|
||||
}
|
||||
|
||||
/// Sends a DATA command
|
||||
pub fn data(&mut self) -> EmailResult {
|
||||
pub fn data(&mut self) -> SmtpResult {
|
||||
self.command("DATA")
|
||||
}
|
||||
|
||||
/// Sends a QUIT command
|
||||
pub fn quit(&mut self) -> EmailResult {
|
||||
pub fn quit(&mut self) -> SmtpResult {
|
||||
self.command("QUIT")
|
||||
}
|
||||
|
||||
/// Sends a NOOP command
|
||||
pub fn noop(&mut self) -> EmailResult {
|
||||
pub fn noop(&mut self) -> SmtpResult {
|
||||
self.command("NOOP")
|
||||
}
|
||||
|
||||
/// Sends a HELP command
|
||||
pub fn help(&mut self, argument: Option<&str>) -> EmailResult {
|
||||
pub fn help(&mut self, argument: Option<&str>) -> SmtpResult {
|
||||
match argument {
|
||||
Some(ref argument) => self.command(&format!("HELP {}", argument)),
|
||||
None => self.command("HELP"),
|
||||
@@ -171,22 +171,22 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
|
||||
}
|
||||
|
||||
/// Sends a VRFY command
|
||||
pub fn vrfy(&mut self, address: &str) -> EmailResult {
|
||||
pub fn vrfy(&mut self, address: &str) -> SmtpResult {
|
||||
self.command(&format!("VRFY {}", address))
|
||||
}
|
||||
|
||||
/// Sends a EXPN command
|
||||
pub fn expn(&mut self, address: &str) -> EmailResult {
|
||||
pub fn expn(&mut self, address: &str) -> SmtpResult {
|
||||
self.command(&format!("EXPN {}", address))
|
||||
}
|
||||
|
||||
/// Sends a RSET command
|
||||
pub fn rset(&mut self) -> EmailResult {
|
||||
pub fn rset(&mut self) -> SmtpResult {
|
||||
self.command("RSET")
|
||||
}
|
||||
|
||||
/// Sends an AUTH command with the given mechanism
|
||||
pub fn auth(&mut self, mechanism: Mechanism, username: &str, password: &str) -> EmailResult {
|
||||
pub fn auth(&mut self, mechanism: Mechanism, username: &str, password: &str) -> SmtpResult {
|
||||
|
||||
if mechanism.supports_initial_response() {
|
||||
self.command(&format!("AUTH {} {}",
|
||||
@@ -209,17 +209,17 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
|
||||
}
|
||||
|
||||
/// Sends a STARTTLS command
|
||||
pub fn starttls(&mut self) -> EmailResult {
|
||||
pub fn starttls(&mut self) -> SmtpResult {
|
||||
self.command("STARTTLS")
|
||||
}
|
||||
|
||||
/// Sends the message content
|
||||
pub fn message(&mut self, message_content: &str) -> EmailResult {
|
||||
pub fn message(&mut self, message_content: &str) -> SmtpResult {
|
||||
self.send_server(&escape_dot(message_content), MESSAGE_ENDING)
|
||||
}
|
||||
|
||||
/// Sends a string to the server and gets the response
|
||||
fn send_server(&mut self, string: &str, end: &str) -> EmailResult {
|
||||
fn send_server(&mut self, string: &str, end: &str) -> SmtpResult {
|
||||
if self.stream.is_none() {
|
||||
return Err(From::from("Connection closed"));
|
||||
}
|
||||
@@ -233,7 +233,7 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
|
||||
}
|
||||
|
||||
/// Gets the SMTP response
|
||||
fn get_reply(&mut self) -> EmailResult {
|
||||
fn get_reply(&mut self) -> SmtpResult {
|
||||
|
||||
let mut parser = ResponseParser::default();
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
//! A trait to represent a stream
|
||||
|
||||
|
||||
use openssl::ssl::{SslContext, SslStream};
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io;
|
||||
use std::io::{ErrorKind, Read, Write};
|
||||
use std::net::{SocketAddr, TcpStream};
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
use openssl::ssl::{SslContext, SslStream};
|
||||
|
||||
/// A trait for the concept of opening a stream
|
||||
pub trait Connector: Sized {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//! Error and result type for SMTP clients
|
||||
|
||||
use std::error::Error as StdError;
|
||||
use std::io;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use transport::smtp::response::{Response, Severity};
|
||||
use rustc_serialize::base64::FromBase64Error;
|
||||
use self::Error::*;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io;
|
||||
|
||||
use transport::smtp::response::{Response, Severity};
|
||||
|
||||
/// An enum of all error kinds.
|
||||
#[derive(Debug)]
|
||||
@@ -82,4 +82,4 @@ impl From<&'static str> for Error {
|
||||
}
|
||||
|
||||
/// SMTP result type
|
||||
pub type EmailResult = Result<Response, Error>;
|
||||
pub type SmtpResult = Result<Response, Error>;
|
||||
@@ -1,14 +1,14 @@
|
||||
//! ESMTP features
|
||||
|
||||
use std::result::Result;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use transport::error::Error;
|
||||
use transport::smtp::response::Response;
|
||||
use std::result::Result;
|
||||
use transport::smtp::authentication::Mechanism;
|
||||
|
||||
use transport::smtp::error::Error;
|
||||
use transport::smtp::response::Response;
|
||||
|
||||
/// Supported ESMTP keywords
|
||||
#[derive(PartialEq,Eq,Hash,Clone,Debug)]
|
||||
pub enum Extension {
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
//! Sends an email using the client
|
||||
|
||||
use std::string::String;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use email::SendableEmail;
|
||||
|
||||
use openssl::ssl::{SslContext, SslMethod};
|
||||
|
||||
use transport::error::{EmailResult, Error};
|
||||
use transport::smtp::extension::{Extension, ServerInfo};
|
||||
use transport::smtp::client::Client;
|
||||
use transport::smtp::authentication::Mechanism;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use std::string::String;
|
||||
use transport::EmailTransport;
|
||||
use email::SendableEmail;
|
||||
use transport::smtp::authentication::Mechanism;
|
||||
use transport::smtp::client::Client;
|
||||
|
||||
use transport::smtp::error::{SmtpResult, Error};
|
||||
use transport::smtp::extension::{Extension, ServerInfo};
|
||||
|
||||
pub mod extension;
|
||||
pub mod authentication;
|
||||
pub mod response;
|
||||
pub mod client;
|
||||
pub mod error;
|
||||
|
||||
// Registrated port numbers:
|
||||
// https://www.iana.
|
||||
@@ -256,7 +257,7 @@ impl SmtpTransport {
|
||||
}
|
||||
|
||||
/// Gets the EHLO response and updates server information
|
||||
pub fn get_ehlo(&mut self) -> EmailResult {
|
||||
pub fn get_ehlo(&mut self) -> SmtpResult {
|
||||
// Extended Hello
|
||||
let ehlo_response = try_smtp!(self.client.ehlo(&self.client_info.hello_name), self);
|
||||
|
||||
@@ -269,9 +270,9 @@ impl SmtpTransport {
|
||||
}
|
||||
}
|
||||
|
||||
impl EmailTransport for SmtpTransport {
|
||||
impl EmailTransport<SmtpResult> for SmtpTransport {
|
||||
/// Sends an email
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult {
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> SmtpResult {
|
||||
|
||||
// Extract email information
|
||||
let message_id = email.message_id();
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
//! SMTP response, containing a mandatory return code and an optional text
|
||||
//! message
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
use std::result;
|
||||
use self::Category::*;
|
||||
|
||||
use self::Severity::*;
|
||||
use self::Category::*;
|
||||
use transport::error::{EmailResult, Error};
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
use std::result;
|
||||
use std::str::FromStr;
|
||||
use transport::smtp::error::{Error, SmtpResult};
|
||||
|
||||
|
||||
/// First digit indicates severity
|
||||
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
|
||||
@@ -183,7 +184,7 @@ impl ResponseParser {
|
||||
}
|
||||
|
||||
/// Builds a response from a `ResponseParser`
|
||||
pub fn response(self) -> EmailResult {
|
||||
pub fn response(self) -> SmtpResult {
|
||||
match self.code {
|
||||
Some(code) => Ok(Response::new(code, self.message)),
|
||||
None => {
|
||||
|
||||
37
src/transport/stub/error.rs
Normal file
37
src/transport/stub/error.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
//! Error and result type for file transport
|
||||
|
||||
use self::Error::*;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
/// An enum of all error kinds.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Internal client error
|
||||
Client(&'static str),
|
||||
}
|
||||
|
||||
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(_) => "an unknown error occured",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Error {
|
||||
fn from(string: &'static str) -> Error {
|
||||
Client(string)
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,25 @@
|
||||
//! This transport is a stub that only logs the message, and always returns
|
||||
//! success
|
||||
|
||||
use transport::error::EmailResult;
|
||||
use transport::smtp::response::{Category, Code, Response, Severity};
|
||||
use transport::EmailTransport;
|
||||
use email::SendableEmail;
|
||||
use transport::EmailTransport;
|
||||
|
||||
pub mod error;
|
||||
|
||||
/// This transport does nothing except logging the message envelope
|
||||
pub struct StubEmailTransport;
|
||||
|
||||
impl EmailTransport for StubEmailTransport {
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult {
|
||||
/// SMTP result type
|
||||
pub type StubResult = Result<(), error::Error>;
|
||||
|
||||
impl EmailTransport<StubResult> for StubEmailTransport {
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> StubResult {
|
||||
|
||||
info!("{}: from=<{}> to=<{:?}>",
|
||||
email.message_id(),
|
||||
email.from_address(),
|
||||
email.to_addresses());
|
||||
Ok(Response::new(Code::new(Severity::PositiveCompletion, Category::MailSystem, 0),
|
||||
vec!["Ok: email logged".to_string()]))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
|
||||
Reference in New Issue
Block a user