use std::{ fs::File, io::Read, path::Path, sync::{mpsc::Receiver, LazyLock}, thread, }; use lettre::{ message::{header::ContentType, Mailbox}, transport::smtp::{ authentication::{Credentials, Mechanism}, PoolConfig, }, AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor, }; use tokio::runtime::Handle; use super::UserConfirmationMessage; static CREDENTIALS: LazyLock = LazyLock::new(|| { Credentials::new( "donotreply@mail.dziura.cloud".to_owned(), "hunter2".to_owned(), ) }); static NUM_CPUS: LazyLock = LazyLock::new(|| num_cpus::get() as u32); static FROM_MAILBOX: LazyLock = LazyLock::new(|| { "No Not Reply Auth-Test " .parse() .unwrap() }); pub fn start_emailer_service( runtime: Handle, assets_dir: &Path, email_message_rx: Receiver, ) { let new_user_confirmation_template_path = assets_dir.join("new-user-confirmation.html"); // TODO: Validate that the new user confirmation template exists let mut new_user_confirmation_template_text = String::with_capacity(8000); File::open(new_user_confirmation_template_path) .and_then(|mut file| file.read_to_string(&mut new_user_confirmation_template_text)) .unwrap(); thread::spawn(move || { while let Some(message) = email_message_rx.iter().next() { let new_user_confirmation_template_text = new_user_confirmation_template_text.clone(); let UserConfirmationMessage { email: recipient_email, name, user_id, verification_token, } = message; runtime.spawn(async move { send_new_user_confirmation_email( recipient_email.as_str(), new_user_confirmation_template_text.as_str(), name.as_str(), user_id, verification_token.as_str(), ) .await; }); } }); } async fn send_new_user_confirmation_email( recipient_email: &str, new_user_confirmation_template_text: &str, name: &str, user_id: i32, verification_token: &str, ) { let body = new_user_confirmation_template_text .replace("$NAME", name) .replace("$USER_ID", user_id.to_string().as_str()) .replace("$VERIFICATION_TOKEN", verification_token); let message = Message::builder() .from(FROM_MAILBOX.clone()) .reply_to(FROM_MAILBOX.clone()) .to(recipient_email.parse().unwrap()) .subject(format!( "You're registered, {name}, please confirm your email address" )) .header(ContentType::TEXT_HTML) .body(body) .unwrap(); let sender: AsyncSmtpTransport = AsyncSmtpTransport::::starttls_relay("mail.dziura.cloud") .unwrap() .credentials(CREDENTIALS.clone()) .authentication(vec![Mechanism::Plain]) .pool_config(PoolConfig::new().max_size(*NUM_CPUS)) .build(); let _ = sender.send(message).await; }