feat: add testmail command

This commit is contained in:
Max Hohlfeld 2025-01-22 09:17:23 +01:00
parent ee9c4b1ac1
commit 8ba2effdbc
3 changed files with 56 additions and 21 deletions

View File

@ -35,9 +35,9 @@ async fn main() -> anyhow::Result<()> {
let args = parse_args()?;
let pool = PgPool::connect(&config.database_url).await?;
let mailer = utils::email::get_mailer()?;
let mailer = utils::email::get_mailer(&config)?;
handle_command(args.command, &pool).await?;
handle_command(args.command, &pool, &mailer).await?;
let address = config.server_address;
let port = config.server_port;

View File

@ -1,5 +1,6 @@
use std::env;
use brass_config::{Config, SmtpTlsType};
use lettre::{
message::{header::ContentType, Mailbox, MultiPart, SinglePart},
transport::smtp::{authentication::Credentials, extension::ClientId},
@ -10,30 +11,19 @@ use crate::models::User;
use super::ApplicationError;
pub fn get_mailer() -> anyhow::Result<SmtpTransport> {
let server = &env::var("SMTP_SERVER")?;
let port = &env::var("SMTP_PORT")?.parse()?;
let login = &env::var("SMTP_LOGIN")
.and_then(|x| Ok(Some(x)))
.unwrap_or(None);
let password = &env::var("SMTP_PASSWORD")
.and_then(|x| Ok(Some(x)))
.unwrap_or(None);
let tls_type = &env::var("SMTP_TLSTYPE")?;
let hostname = &env::var("HOSTNAME")?;
let mut builder = match tls_type.as_str() {
"starttls" => SmtpTransport::starttls_relay(server)?.port(*port),
"tls" => SmtpTransport::relay(server)?.port(*port),
_ => SmtpTransport::builder_dangerous(server).port(*port),
pub fn get_mailer(config: &Config) -> anyhow::Result<SmtpTransport> {
let mut builder = match config.smtp_tlstype {
SmtpTlsType::StartTLS => SmtpTransport::starttls_relay(&config.smtp_server)?.port(config.smtp_port),
SmtpTlsType::TLS => SmtpTransport::relay(&config.smtp_server)?.port(config.smtp_port),
SmtpTlsType::NoTLS => SmtpTransport::builder_dangerous(&config.smtp_server).port(config.smtp_port),
};
if let (Some(login), Some(password)) = (login, password) {
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 mailer = builder
.hello_name(ClientId::Domain(hostname.to_string()))
.hello_name(ClientId::Domain(config.hostname.clone()))
.build();
Ok(mailer)

View File

@ -1,8 +1,13 @@
use std::{
error::Error,
io::{stdin, stdout, Write},
process::exit,
};
use lettre::{
message::{header::ContentType, SinglePart},
Message, SmtpTransport, Transport,
};
use sqlx::{Pool, Postgres};
use crate::{
@ -13,6 +18,7 @@ use crate::{
pub enum Command {
Migrate,
CreateAdmin,
TestMail(String),
}
pub struct Args {
@ -23,6 +29,7 @@ pub fn parse_args() -> Result<Args, pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();
let command = pargs.free_from_str::<String>();
let argument = pargs.opt_free_from_str::<String>()?;
let mut args = Args { command: None };
@ -30,6 +37,14 @@ pub fn parse_args() -> Result<Args, pico_args::Error> {
match parsed.trim() {
"migrate" => args.command = Some(Command::Migrate),
"createadmin" => args.command = Some(Command::CreateAdmin),
"testmail" => {
if let Some(to) = argument {
args.command = Some(Command::TestMail(to))
} else {
eprintln!("Testmail command requires an email. Use it like this 'brass testmail abc@example.com'");
exit(1)
}
}
_ => (),
}
}
@ -47,7 +62,11 @@ fn prompt(prompt: &str) -> anyhow::Result<String> {
Ok(input.trim().to_string())
}
pub async fn handle_command(command: Option<Command>, pool: &Pool<Postgres>) -> anyhow::Result<()> {
pub async fn handle_command(
command: Option<Command>,
pool: &Pool<Postgres>,
mailer: &SmtpTransport,
) -> anyhow::Result<()> {
match command {
Some(Command::Migrate) => {
sqlx::migrate!("../migrations").run(pool).await?;
@ -81,6 +100,32 @@ pub async fn handle_command(command: Option<Command>, pool: &Pool<Postgres>) ->
exit(0);
}
Some(Command::TestMail(to)) => {
let message = Message::builder()
.from("noreply <noreply@brasiwa-leipzig.de>".parse().unwrap())
.reply_to("noreply <noreply@brasiwa-leipzig.de>".parse().unwrap())
.to(to.parse().unwrap())
.subject("Brass: Test E-Mail")
.singlepart(
SinglePart::builder()
.header(ContentType::TEXT_HTML)
.body("Testmail von Brass. E-Mail Versand funktioniert!".to_string()),
)
.unwrap();
match mailer.send(&message) {
Ok(_) => println!("Successfully sent mail to {to}."),
Err(e) => {
if let Some(source) = e.source() {
eprintln!("Error sending mail with error source: {source}");
} else {
eprintln!("Error sending mail with unkown error source.");
}
}
}
exit(0);
}
None => (),
};