use std::borrow::Cow;
use lettre::{
Address, AsyncSmtpTransport, AsyncTransport, Message, message::Mailbox,
transport::smtp::response::Severity,
};
use crate::{EmailEnvelopeDetails, MailListError, MailListResult};
#[derive(Debug)]
pub struct Smtps {
pub(crate) domain: Cow<'static, str>,
pub(crate) from: Mailbox,
pub(crate) reply_to: Option<Mailbox>,
pub(crate) ehlo_name: Option<Cow<'static, str>>,
#[cfg(feature = "tokio-runtime")]
pub(crate) mailer: AsyncSmtpTransport<lettre::Tokio1Executor>,
}
impl Smtps {
pub fn set_reply_to(
&mut self,
reply_to_name: &str,
reply_to_address: &str,
) -> MailListResult<&mut Self> {
self.reply_to.replace(Mailbox::new(
Some(reply_to_name.to_string()),
reply_to_address
.parse::<Address>()
.map_err(|error| MailListError::Mailer(error.to_string()))?,
));
Ok(self)
}
pub fn domain(&self) -> &str {
self.domain.as_ref()
}
pub fn ehlo_name(&self) -> Option<&Cow<'_, str>> {
self.ehlo_name.as_ref()
}
pub fn from(&self) -> &Mailbox {
&self.from
}
pub fn reply_to(&self) -> Option<&Mailbox> {
self.reply_to.as_ref()
}
#[cfg(feature = "tokio-runtime")]
pub fn mailer(&self) -> &AsyncSmtpTransport<lettre::Tokio1Executor> {
&self.mailer
}
pub async fn send(&self, message: &EmailEnvelopeDetails) -> MailListResult<()> {
let email = Message::builder().from(self.from().clone());
let email = if let Some(reply_to) = self.reply_to() {
email.reply_to(reply_to.clone())
} else {
email
};
let email = email
.to(message
.to
.parse::<Mailbox>()
.map_err(|error| MailListError::Mailer(error.to_string()))?)
.subject(message.subject.as_str())
.header(lettre::message::header::ContentType::TEXT_HTML)
.body(message.body.to_string())
.map_err(|error| MailListError::Mailer(error.to_string()))?;
let response = self
.mailer
.send(email)
.await
.map_err(|error| MailListError::MailDelivery(error.to_string()))?;
if response.code().severity == Severity::PositiveCompletion {
Ok(())
} else {
Err(MailListError::Smtps(
response.message().map(|msg| msg.to_string()).collect(),
))
}
}
pub async fn test_connection(&self) -> MailListResult<bool> {
self.mailer
.test_connection()
.await
.map_err(|error| MailListError::Mailer(error.to_string()))
}
}