Update dependencies and implement email service integration

- Refactor app and email modules to include email service
- Add tests for user sign-up and mock email service
This commit is contained in:
Greg Burri 2025-05-02 00:57:32 +02:00
parent f31167dd95
commit 3626f8a11b
10 changed files with 291 additions and 151 deletions

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use lettre::{
AsyncTransport, Message, Tokio1Executor,
transport::smtp::{AsyncSmtpTransport, authentication::Credentials},
@ -18,33 +20,52 @@ pub enum Error {
Email(#[from] lettre::error::Error),
}
/// A function to send an email using the given SMTP address.
/// It may timeout if the SMTP server is not reachable, see [consts::SEND_EMAIL_TIMEOUT].
pub async fn send_email(
email: &str,
title: &str,
message: &str,
smtp_relay_address: &str,
smtp_login: &str,
smtp_password: &str,
) -> Result<(), Error> {
let email = Message::builder()
.message_id(None)
.from(consts::EMAIL_ADDRESS.parse()?)
.to(email.parse()?)
.subject(title)
.body(message.to_string())?;
let credentials = Credentials::new(smtp_login.to_string(), smtp_password.to_string());
let mailer = AsyncSmtpTransport::<Tokio1Executor>::relay(smtp_relay_address)?
.credentials(credentials)
.timeout(Some(consts::SEND_EMAIL_TIMEOUT))
.build();
if let Err(error) = mailer.send(email).await {
error!("Error when sending E-mail: {}", &error);
}
Ok(())
#[async_trait::async_trait]
pub trait EmailServiceTrait: Send + Sync {
async fn send_email(&self, email: &str, title: &str, message: &str) -> Result<(), Error>;
}
pub struct EmailService {
smtp_relay_address: String,
smtp_login: String,
smtp_password: String,
}
impl EmailService {
pub fn create_service(
smtp_relay_address: &str,
smtp_login: &str,
smtp_password: &str,
) -> Arc<dyn EmailServiceTrait> {
Arc::new(Self {
smtp_relay_address: smtp_relay_address.to_string(),
smtp_login: smtp_login.to_string(),
smtp_password: smtp_password.to_string(),
})
}
}
#[async_trait::async_trait]
impl EmailServiceTrait for EmailService {
/// A function to send an email using the given SMTP address.
/// It may timeout if the SMTP server is not reachable, see [consts::SEND_EMAIL_TIMEOUT].
async fn send_email(&self, email: &str, title: &str, message: &str) -> Result<(), Error> {
let email = Message::builder()
.message_id(None)
.from(consts::EMAIL_ADDRESS.parse()?)
.to(email.parse()?)
.subject(title)
.body(message.to_string())?;
let credentials = Credentials::new(self.smtp_login.clone(), self.smtp_password.clone());
let mailer = AsyncSmtpTransport::<Tokio1Executor>::relay(&self.smtp_relay_address)?
.credentials(credentials)
.timeout(Some(consts::SEND_EMAIL_TIMEOUT))
.build();
mailer.send(email).await?;
Ok(())
}
}