#![doc(html_root_url = "https://docs.rs/lettre/0.8.2")]
#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
unused_qualifications)]
#[cfg(feature = "smtp-transport")]
extern crate base64;
#[cfg(feature = "smtp-transport")]
extern crate bufstream;
#[cfg(feature = "crammd5-auth")]
extern crate hex;
#[cfg(feature = "crammd5-auth")]
extern crate hmac;
#[cfg(feature = "smtp-transport")]
extern crate hostname;
#[macro_use]
extern crate log;
#[cfg(feature = "crammd5-auth")]
extern crate md5;
#[cfg(feature = "smtp-transport")]
extern crate native_tls;
#[cfg(feature = "smtp-transport")]
#[macro_use]
extern crate nom;
#[cfg(feature = "serde-impls")]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "file-transport")]
extern crate serde_json;
#[cfg(feature = "smtp-transport")]
pub mod smtp;
#[cfg(feature = "sendmail-transport")]
pub mod sendmail;
pub mod stub;
#[cfg(feature = "file-transport")]
pub mod file;
#[cfg(feature = "file-transport")]
pub use file::FileEmailTransport;
#[cfg(feature = "sendmail-transport")]
pub use sendmail::SendmailTransport;
#[cfg(feature = "smtp-transport")]
pub use smtp::{ClientSecurity, SmtpTransport};
#[cfg(feature = "smtp-transport")]
pub use smtp::client::net::ClientTlsParameters;
use std::fmt::{self, Display, Formatter};
use std::io::Read;
use std::error::Error as StdError;
use std::str::FromStr;
#[derive(Debug, Clone, Copy)]
pub enum Error {
MissingFrom,
MissingTo,
InvalidEmailAddress,
}
impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::MissingFrom => "missing source address, invalid envelope",
Error::MissingTo => "missing destination address, invalid envelope",
Error::InvalidEmailAddress => "invalid email address",
}
}
fn cause(&self) -> Option<&StdError> {
None
}
}
impl Display for Error {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
fmt.write_str(self.description())
}
}
pub type EmailResult<T> = Result<T, Error>;
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct EmailAddress(String);
impl EmailAddress {
pub fn new(address: String) -> EmailResult<EmailAddress> {
Ok(EmailAddress(address))
}
}
impl FromStr for EmailAddress {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
EmailAddress::new(s.to_string())
}
}
impl Display for EmailAddress {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(&self.0)
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct Envelope {
forward_path: Vec<EmailAddress>,
reverse_path: Option<EmailAddress>,
}
impl Envelope {
pub fn new(from: Option<EmailAddress>, to: Vec<EmailAddress>) -> EmailResult<Envelope> {
if to.is_empty() {
return Err(Error::MissingTo);
}
Ok(Envelope {
forward_path: to,
reverse_path: from,
})
}
pub fn to(&self) -> &[EmailAddress] {
self.forward_path.as_slice()
}
pub fn from(&self) -> Option<&EmailAddress> {
self.reverse_path.as_ref()
}
pub fn builder() -> EnvelopeBuilder {
EnvelopeBuilder::new()
}
}
#[derive(PartialEq, Eq, Clone, Debug, Default)]
pub struct EnvelopeBuilder {
to: Vec<EmailAddress>,
from: Option<EmailAddress>,
}
impl EnvelopeBuilder {
pub fn new() -> Self {
EnvelopeBuilder {
to: vec![],
from: None,
}
}
pub fn to<S: Into<EmailAddress>>(mut self, address: S) -> Self {
self.add_to(address);
self
}
pub fn add_to<S: Into<EmailAddress>>(&mut self, address: S) {
self.to.push(address.into());
}
pub fn from<S: Into<EmailAddress>>(mut self, address: S) -> Self {
self.set_from(address);
self
}
pub fn set_from<S: Into<EmailAddress>>(&mut self, address: S) {
self.from = Some(address.into());
}
pub fn build(self) -> EmailResult<Envelope> {
Envelope::new(self.from, self.to)
}
}
pub trait SendableEmail<'a, T: Read + 'a> {
fn envelope(&self) -> Envelope;
fn message_id(&self) -> String;
fn message(&'a self) -> Box<T>;
}
pub trait EmailTransport<'a, U: Read + 'a, V> {
fn send<T: SendableEmail<'a, U> + 'a>(&mut self, email: &'a T) -> V;
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct SimpleSendableEmail {
envelope: Envelope,
message_id: String,
message: Vec<u8>,
}
impl SimpleSendableEmail {
pub fn new(
from_address: String,
to_addresses: &[String],
message_id: String,
message: String,
) -> EmailResult<SimpleSendableEmail> {
let to: Result<Vec<EmailAddress>, Error> = to_addresses
.iter()
.map(|x| EmailAddress::new(x.clone()))
.collect();
Ok(SimpleSendableEmail::new_with_envelope(
Envelope::new(Some(EmailAddress::new(from_address)?), to?)?,
message_id,
message,
))
}
pub fn new_with_envelope(
envelope: Envelope,
message_id: String,
message: String,
) -> SimpleSendableEmail {
SimpleSendableEmail {
envelope,
message_id,
message: message.into_bytes(),
}
}
}
impl<'a> SendableEmail<'a, &'a [u8]> for SimpleSendableEmail {
fn envelope(&self) -> Envelope {
self.envelope.clone()
}
fn message_id(&self) -> String {
self.message_id.clone()
}
fn message(&'a self) -> Box<&[u8]> {
Box::new(self.message.as_slice())
}
}