diff --git a/src/email/mod.rs b/src/email/mod.rs index d04dd02..b8d0652 100644 --- a/src/email/mod.rs +++ b/src/email/mod.rs @@ -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()); } diff --git a/src/lib.rs b/src/lib.rs index 1029c49..f9524b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 diff --git a/src/transport/file/mod.rs b/src/transport/file/mod.rs index 61dac35..dd1ce1a 100644 --- a/src/transport/file/mod.rs +++ b/src/transport/file/mod.rs @@ -38,7 +38,7 @@ impl EmailTransport 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=", log_line); diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 36d7998..a007604 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -1,6 +1,7 @@ //! Represents an Email transport pub mod smtp; +pub mod sendmail; pub mod stub; pub mod file; diff --git a/src/transport/sendmail/error.rs b/src/transport/sendmail/error.rs new file mode 100644 index 0000000..5db1cf7 --- /dev/null +++ b/src/transport/sendmail/error.rs @@ -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 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>; diff --git a/src/transport/sendmail/mod.rs b/src/transport/sendmail/mod.rs new file mode 100644 index 0000000..cb19b62 --- /dev/null +++ b/src/transport/sendmail/mod.rs @@ -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>(command: S) -> SendmailTransport { + SendmailTransport { command: command.into() } + } +} + +impl EmailTransport for SendmailTransport { + fn send(&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) { + () + } +} diff --git a/tests/lib.rs b/tests/lib.rs index 45a6ab9..1e446d5 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,5 +1,6 @@ extern crate lettre; mod transport_smtp; +mod transport_sendmail; mod transport_stub; mod transport_file; diff --git a/tests/transport_file.rs b/tests/transport_file.rs index 01ea837..8c0beb5 100644 --- a/tests/transport_file.rs +++ b/tests/transport_file.rs @@ -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()); diff --git a/tests/transport_sendmail.rs b/tests/transport_sendmail.rs new file mode 100644 index 0000000..3586d34 --- /dev/null +++ b/tests/transport_sendmail.rs @@ -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()); +} diff --git a/tests/transport_smtp.rs b/tests/transport_smtp.rs index 9af40d5..44f3d48 100644 --- a/tests/transport_smtp.rs +++ b/tests/transport_smtp.rs @@ -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()); } diff --git a/tests/transport_stub.rs b/tests/transport_stub.rs index 9e4b18a..468cb80 100644 --- a/tests/transport_stub.rs +++ b/tests/transport_stub.rs @@ -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()); }