Merge pull request #104 from amousset/sendmail

test(transport): add sendmail transport
This commit is contained in:
Alexis Mousset
2016-10-23 20:57:43 +02:00
committed by GitHub
11 changed files with 185 additions and 29 deletions

View File

@@ -82,8 +82,6 @@ impl IntoEmail for SimpleEmail {
builder.add_cc(cc_address.into_mailbox());
}
// No bcc for now
if self.reply_to.is_some() {
builder.add_reply_to(self.reply_to.unwrap().into_mailbox());
}

View File

@@ -180,6 +180,28 @@
//! let _ = email_client.quit();
//! ```
//!
//! ### Sendmail transport
//!
//! The sendmail transport sends the email using the local sendmail command.
//!
//! ```rust
//! use lettre::transport::sendmail::SendmailTransport;
//! use lettre::transport::EmailTransport;
//! use lettre::email::EmailBuilder;
//!
//! let email = EmailBuilder::new()
//! .to("root@localhost")
//! .from("user@localhost")
//! .body("Hello World!")
//! .subject("Hello")
//! .build()
//! .unwrap();
//!
//! let mut sender = SendmailTransport::new();
//! let result = sender.send(email);
//! assert!(result.is_ok());
//! ```
//!
//! ### Stub transport
//!
//! The stub transport only logs message envelope and drops the content. It can be useful for

View File

@@ -38,7 +38,7 @@ impl EmailTransport<FileResult> for FileEmailTransport {
email.to_addresses().join("> to=<"));
try!(f.write_all(log_line.as_bytes()));
try!(f.write_all(email.message().clone().as_bytes()));
try!(f.write_all(email.message().as_bytes()));
info!("{} status=<written>", log_line);

View File

@@ -1,6 +1,7 @@
//! Represents an Email transport
pub mod smtp;
pub mod sendmail;
pub mod stub;
pub mod file;

View File

@@ -0,0 +1,54 @@
//! Error and result type for sendmail 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)
}
}
/// SendMail result type
pub type SendmailResult = Result<(), Error>;

View File

@@ -0,0 +1,60 @@
//! This transport uilizes the sendmail executable for each email.
use email::SendableEmail;
use std::io::prelude::*;
use std::process::{Command, Stdio};
use transport::EmailTransport;
use transport::sendmail::error::SendmailResult;
pub mod error;
/// Sends an email using the `sendmail` command
#[derive(Debug,Default)]
pub struct SendmailTransport {
command: String,
}
impl SendmailTransport {
/// Creates a new transport with the default `/usr/sbin/sendmail` command
pub fn new() -> SendmailTransport {
SendmailTransport { command: "/usr/sbin/sendmail".to_string() }
}
/// Creates a new transport to the given sendmail command
pub fn new_with_command<S: Into<String>>(command: S) -> SendmailTransport {
SendmailTransport { command: command.into() }
}
}
impl EmailTransport<SendmailResult> for SendmailTransport {
fn send<T: SendableEmail>(&mut self, email: T) -> SendmailResult {
// Spawn the sendmail command
let mut process = try!(Command::new(&self.command)
.args(&["-i", "-f", &email.from_address(), &email.to_addresses().join(" ")])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn());
match process.stdin.as_mut().unwrap().write_all(email.message().as_bytes()) {
Ok(_) => (),
Err(error) => return Err(From::from(error)),
}
info!("Wrote message to stdin");
if let Ok(output) = process.wait_with_output() {
if output.status.success() {
Ok(())
} else {
Err(From::from("The message could not be sent"))
}
} else {
Err(From::from("The sendmail process stopped"))
}
}
fn close(&mut self) {
()
}
}

View File

@@ -1,5 +1,6 @@
extern crate lettre;
mod transport_smtp;
mod transport_sendmail;
mod transport_stub;
mod transport_file;

View File

@@ -1,24 +1,24 @@
extern crate lettre;
use lettre::email::{EmailBuilder, SendableEmail};
use lettre::transport::EmailTransport;
use lettre::transport::file::FileEmailTransport;
use std::env::temp_dir;
use std::fs::File;
use std::fs::remove_file;
use std::io::Read;
use lettre::transport::file::FileEmailTransport;
use lettre::transport::EmailTransport;
use lettre::email::{EmailBuilder, SendableEmail};
#[test]
fn file_transport() {
let mut sender = FileEmailTransport::new(temp_dir());
let email = EmailBuilder::new()
.to("root@localhost")
.from("user@localhost")
.body("Hello World!")
.subject("Hello")
.build()
.unwrap();
.to("root@localhost")
.from("user@localhost")
.body("Hello World!")
.subject("Hello file")
.build()
.unwrap();
let result = sender.send(email.clone());
assert!(result.is_ok());

View File

@@ -0,0 +1,20 @@
extern crate lettre;
use lettre::email::EmailBuilder;
use lettre::transport::EmailTransport;
use lettre::transport::sendmail::SendmailTransport;
#[test]
fn sendmail_transport_simple() {
let mut sender = SendmailTransport::new();
let email = EmailBuilder::new()
.to("root@localhost")
.from("user@localhost")
.body("Hello World!")
.subject("Hello sendmail")
.build()
.unwrap();
let result = sender.send(email);
println!("{:?}", result);
assert!(result.is_ok());
}

View File

@@ -1,19 +1,19 @@
extern crate lettre;
use lettre::transport::smtp::SmtpTransportBuilder;
use lettre::transport::EmailTransport;
use lettre::email::EmailBuilder;
use lettre::transport::EmailTransport;
use lettre::transport::smtp::SmtpTransportBuilder;
#[test]
fn smtp_transport_simple() {
let mut sender = SmtpTransportBuilder::localhost().unwrap().build();
let email = EmailBuilder::new()
.to("root@localhost")
.from("user@localhost")
.body("Hello World!")
.subject("Hello")
.build()
.unwrap();
.to("root@localhost")
.from("user@localhost")
.body("Hello World!")
.subject("Hello smtp")
.build()
.unwrap();
let result = sender.send(email);
assert!(result.is_ok());
}

View File

@@ -1,19 +1,19 @@
extern crate lettre;
use lettre::transport::stub::StubEmailTransport;
use lettre::transport::EmailTransport;
use lettre::email::EmailBuilder;
use lettre::transport::EmailTransport;
use lettre::transport::stub::StubEmailTransport;
#[test]
fn stub_transport() {
let mut sender = StubEmailTransport;
let email = EmailBuilder::new()
.to("root@localhost")
.from("user@localhost")
.body("Hello World!")
.subject("Hello")
.build()
.unwrap();
.to("root@localhost")
.from("user@localhost")
.body("Hello World!")
.subject("Hello stub")
.build()
.unwrap();
let result = sender.send(email);
assert!(result.is_ok());
}