first commit
This commit is contained in:
commit
2eb8aac027
91 files changed
+20139
No files matched your search
@@ -0,0 +1,86 @@
|
||||
use lettre::{
|
||||
AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor,
|
||||
message::Mailbox,
|
||||
transport::smtp::{authentication::Credentials, extension::ClientId},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
config::AppConfig,
|
||||
error::{AppError, AppResult},
|
||||
};
|
||||
|
||||
fn transport(config: &AppConfig) -> AppResult<AsyncSmtpTransport<Tokio1Executor>> {
|
||||
let smtp = &config.smtp;
|
||||
let mut builder = match smtp.kind.as_str() {
|
||||
"starttls" => AsyncSmtpTransport::<Tokio1Executor>::starttls_relay(&smtp.host)
|
||||
.map_err(|e| AppError::Mail(e.to_string()))?,
|
||||
"tls" => AsyncSmtpTransport::<Tokio1Executor>::relay(&smtp.host)
|
||||
.map_err(|e| AppError::Mail(e.to_string()))?,
|
||||
_ => AsyncSmtpTransport::<Tokio1Executor>::builder_dangerous(&smtp.host),
|
||||
}
|
||||
.port(smtp.port);
|
||||
|
||||
if !smtp.client_name.trim().is_empty() {
|
||||
builder = builder.hello_name(ClientId::Domain(smtp.client_name.trim().to_string()));
|
||||
}
|
||||
if !smtp.username.is_empty() {
|
||||
builder = builder.credentials(Credentials::new(
|
||||
smtp.username.clone(),
|
||||
smtp.password.clone(),
|
||||
));
|
||||
}
|
||||
Ok(builder.build())
|
||||
}
|
||||
|
||||
pub fn sender_named(
|
||||
config: &AppConfig,
|
||||
fallback: &str,
|
||||
display_name: Option<&str>,
|
||||
) -> AppResult<Mailbox> {
|
||||
let address = if config.smtp.admin_email.is_empty() {
|
||||
fallback
|
||||
} else {
|
||||
&config.smtp.admin_email
|
||||
};
|
||||
let parsed = address
|
||||
.parse()
|
||||
.map_err(|e| AppError::bad_request(format!("invalid sender address: {e}")))?;
|
||||
let name = display_name
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
.unwrap_or(&config.smtp.admin_name);
|
||||
Ok(Mailbox::new(Some(name.to_string()), parsed))
|
||||
}
|
||||
|
||||
pub async fn send_text(
|
||||
config: &AppConfig,
|
||||
from_fallback: &str,
|
||||
to: &str,
|
||||
subject: &str,
|
||||
body: &str,
|
||||
) -> AppResult<()> {
|
||||
send_text_named(config, from_fallback, None, to, subject, body).await
|
||||
}
|
||||
|
||||
pub async fn send_text_named(
|
||||
config: &AppConfig,
|
||||
from_fallback: &str,
|
||||
from_name: Option<&str>,
|
||||
to: &str,
|
||||
subject: &str,
|
||||
body: &str,
|
||||
) -> AppResult<()> {
|
||||
let to: Mailbox = to
|
||||
.parse()
|
||||
.map_err(|e| AppError::bad_request(format!("invalid recipient: {e}")))?;
|
||||
let message = Message::builder()
|
||||
.from(sender_named(config, from_fallback, from_name)?)
|
||||
.to(to)
|
||||
.subject(subject)
|
||||
.body(body.to_owned())
|
||||
.map_err(|e| AppError::Mail(e.to_string()))?;
|
||||
transport(config)?
|
||||
.send(message)
|
||||
.await
|
||||
.map_err(|e| AppError::Mail(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user