brass/web/src/mail/mod.rs

114 lines
3.2 KiB
Rust

use brass_config::{Config, SmtpTlsType};
use lettre::{
address::Envelope,
transport::{
smtp::{authentication::Credentials, extension::ClientId},
stub::AsyncStubTransport,
},
AsyncSmtpTransport, AsyncStd1Executor, AsyncTransport,
};
use crate::utils::ApplicationError;
mod forgot_password;
mod registration;
mod testmail;
#[derive(Clone, Debug)]
pub struct Mailer {
transport: Transports,
hostname: String,
}
#[derive(Clone, Debug)]
enum Transports {
SmtpTransport(AsyncSmtpTransport<AsyncStd1Executor>),
#[allow(unused)]
StubTransport(AsyncStubTransport),
}
impl AsyncTransport for Transports {
type Ok = ();
type Error = ApplicationError;
fn send_raw<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
envelope: &'life1 Envelope,
email: &'life2 [u8],
) -> ::core::pin::Pin<
Box<
dyn ::core::future::Future<Output = Result<Self::Ok, Self::Error>>
+ ::core::marker::Send
+ 'async_trait,
>,
>
where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
{
Box::pin(async move {
match self {
Transports::SmtpTransport(smtp_transport) => smtp_transport
.send_raw(envelope, email)
.await
.map(|_| ())
.map_err(ApplicationError::EmailTransport),
Transports::StubTransport(stub_transport) => stub_transport
.send_raw(envelope, email)
.await
.map(|_| ())
.map_err(ApplicationError::EmailStubTransport),
}
})
}
}
impl Mailer {
pub fn new(config: &Config) -> anyhow::Result<Self> {
let mut builder = match config.smtp_tlstype {
SmtpTlsType::StartTLS => {
AsyncSmtpTransport::<AsyncStd1Executor>::starttls_relay(&config.smtp_server)?
.port(config.smtp_port)
}
SmtpTlsType::TLS => {
AsyncSmtpTransport::<AsyncStd1Executor>::relay(&config.smtp_server)?
.port(config.smtp_port)
}
SmtpTlsType::NoTLS => {
AsyncSmtpTransport::<AsyncStd1Executor>::builder_dangerous(&config.smtp_server)
.port(config.smtp_port)
}
};
if let (Some(login), Some(password)) =
(config.smtp_login.as_ref(), config.smtp_password.as_ref())
{
builder =
builder.credentials(Credentials::new(login.to_string(), password.to_string()));
}
let transport = builder
.hello_name(ClientId::Domain(config.hostname.clone()))
.build();
let mailer = Mailer {
transport: Transports::SmtpTransport(transport),
hostname: config.hostname.to_string(),
};
Ok(mailer)
}
}
#[cfg(test)]
impl Mailer {
pub fn new_stub() -> Self {
Mailer {
transport: Transports::StubTransport(AsyncStubTransport::new_ok()),
hostname: String::from("testhostname"),
}
}
}