use std::borrow::Cow;
use lettre::{AsyncSmtpTransport, message::Mailbox};
use crate::{MailListError, MailListResult, Smtps};
#[derive(Debug, Default)]
pub struct SmtpsBuilder {
from: Cow<'static, str>,
reply_to: Option<Cow<'static, str>>,
hello_name: Option<Cow<'static, str>>,
}
impl SmtpsBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn set_from(&mut self, from: &str) -> &mut Self {
self.from = from.to_string().into();
self
}
pub fn set_reply_to(&mut self, reply_to: &str) -> &mut Self {
self.reply_to.replace(reply_to.to_string().into());
self
}
pub fn set_hello_name(&mut self, hello_name: &str) -> &mut Self {
self.hello_name.replace(hello_name.to_string().into());
self
}
pub fn build(self, smtps_uri: &str) -> MailListResult<Smtps> {
use url::Url;
let url =
Url::parse(smtps_uri).or(Err(MailListError::Smtps("Invalid smtps URI".to_string())))?;
if url.scheme() != "smtps" {
return Err(MailListError::Smtps("Invalid SMTPs scheme".to_string()));
};
let domain = url
.host_str()
.ok_or(MailListError::Smtps(
"Domain not found in SMTPs".to_string(),
))?
.to_string();
let ehlo_name = url.path().trim_start_matches('/');
#[cfg(feature = "tokio-runtime")]
let transport = AsyncSmtpTransport::<lettre::Tokio1Executor>::from_url(smtps_uri)
.map_err(|error| MailListError::Mailer(error.to_string()))?;
let mailer = if let Some(hello_name) = self.hello_name.as_ref() {
transport.hello_name(lettre::transport::smtp::extension::ClientId::Domain(
hello_name.to_string(),
))
} else {
transport
};
let mailer = mailer.build();
let outcome = Smtps {
domain: domain.into(),
from: self
.from
.parse::<Mailbox>()
.map_err(|error| MailListError::Mailer(error.to_string()))?,
reply_to: self
.reply_to
.map(|value| {
value
.parse::<Mailbox>()
.map_err(|error| MailListError::Mailer(error.to_string()))
})
.transpose()?,
ehlo_name: if ehlo_name.is_empty() {
None
} else {
Some(ehlo_name.to_string().into())
},
mailer,
};
Ok(outcome)
}
pub async fn test_connection(self, smtps_uri: &str) -> MailListResult<()> {
#[cfg(feature = "tokio-runtime")]
let transport = AsyncSmtpTransport::<lettre::Tokio1Executor>::from_url(smtps_uri)
.map_err(|error| MailListError::Mailer(error.to_string()))?;
let mailer = if let Some(hello_name) = self.hello_name.as_ref() {
transport.hello_name(lettre::transport::smtp::extension::ClientId::Domain(
hello_name.to_string(),
))
} else {
transport
};
#[cfg(feature = "tokio-runtime")]
let mailer: AsyncSmtpTransport<lettre::Tokio1Executor> = mailer.build();
mailer
.test_connection()
.await
.map_err(|error| MailListError::Mailer(error.to_string()))?;
Ok(())
}
}