feat: mailer adapter: bootstrap smtp client
This commit is contained in:
parent
e60a78054e
commit
ef2c2fec2f
4 changed files with 128 additions and 0 deletions
|
@ -0,0 +1,65 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::identity::application::port::output::mailer::{account_validation_link::*, errors::*};
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl AccountValidationLinkOutMailerPort for LettreMailer {
|
||||||
|
async fn account_validation_link(
|
||||||
|
&self,
|
||||||
|
to: &str,
|
||||||
|
username: &str,
|
||||||
|
validation_secret: &str,
|
||||||
|
) -> OutMailerPortResult<()> {
|
||||||
|
|
||||||
|
let email = Message::builder()
|
||||||
|
.from(&self.from)
|
||||||
|
.reply_to(&self.reply_to)
|
||||||
|
.to(to)
|
||||||
|
.subject("Please validate your account on Vanikam") // TODO: use better title
|
||||||
|
.header(ContentType::TEXT_PLAIN)
|
||||||
|
.body(format!(r#"Hello {username},
|
||||||
|
Please click here to validate your Vanikam account: {validation_secret}
|
||||||
|
Warm regards,
|
||||||
|
Vanikam Admin
|
||||||
|
"#)) // TODO: change signature
|
||||||
|
.unwrap();
|
||||||
|
mailer.send(email).await.unwrap();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: mailer tests
|
||||||
|
|
||||||
|
//#[cfg(test)]
|
||||||
|
//mod tests {
|
||||||
|
// use super::*;
|
||||||
|
//
|
||||||
|
// #[actix_rt::test]
|
||||||
|
// async fn test_postgres_create_verification_secret() {
|
||||||
|
// let settings = crate::settings::tests::get_settings().await;
|
||||||
|
// let db = super::DBOutPostgresAdapter::new(
|
||||||
|
// sqlx::postgres::PgPool::connect(&settings.database.url)
|
||||||
|
// .await
|
||||||
|
// .unwrap(),
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// let msg = CreateSecretMsgBuilder::default()
|
||||||
|
// .secret("secret".into())
|
||||||
|
// .purpose("purpose".into())
|
||||||
|
// .username("username".into())
|
||||||
|
// .build()
|
||||||
|
// .unwrap();
|
||||||
|
//
|
||||||
|
// db.create_verification_secret(msg.clone()).await.unwrap();
|
||||||
|
//
|
||||||
|
// // duplicate: secret exists
|
||||||
|
// assert_eq!(
|
||||||
|
// db.create_verification_secret(msg).await.err(),
|
||||||
|
// Some(OutDBPortError::VerificationOTPSecretExists)
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// settings.drop_db().await;
|
||||||
|
// }
|
||||||
|
//}
|
55
src/identity/adapters/output/mailer/lettre/mod.rs
Normal file
55
src/identity/adapters/output/mailer/lettre/mod.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use lettre::{
|
||||||
|
message::header::ContentType, transport::smtp::authentication::Credentials, AsyncSmtpTransport,
|
||||||
|
Message, Tokio1Executor,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::settings::Settings;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LettreMailer {
|
||||||
|
mailer: AsyncSmtpTransport<Tokio1Executor>,
|
||||||
|
from: String,
|
||||||
|
reply_to: String,
|
||||||
|
to: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LettreMailer {
|
||||||
|
pub async fn new(s: &Settings) -> Self {
|
||||||
|
let email = Message::builder()
|
||||||
|
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||||
|
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
|
||||||
|
.to("Hei <hei@domain.tld>".parse().unwrap())
|
||||||
|
.subject("Happy new async year")
|
||||||
|
.header(ContentType::TEXT_PLAIN)
|
||||||
|
.body(String::from("Be happy with async!"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let creds = Credentials::new("smtp_username".to_owned(), "smtp_password".to_owned());
|
||||||
|
|
||||||
|
// Open a remote connection to gmail
|
||||||
|
let mailer: AsyncSmtpTransport<Tokio1Executor> =
|
||||||
|
AsyncSmtpTransport::<Tokio1Executor>::relay("smtp.gmail.com")
|
||||||
|
.unwrap()
|
||||||
|
.credentials(creds)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
mailer,
|
||||||
|
from: String::default(), // TODO: create settings module to read config
|
||||||
|
to: String::default(),
|
||||||
|
reply_to: String::default(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the email
|
||||||
|
// match mailer.send(email).await {
|
||||||
|
// Ok(_) => println!("Email sent successfully!"),
|
||||||
|
// Err(e) => panic!("Could not send email: {e:?}"),
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
}
|
5
src/identity/adapters/output/mailer/mod.rs
Normal file
5
src/identity/adapters/output/mailer/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
pub mod lettre;
|
|
@ -1,3 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
pub mod db;
|
||||||
|
pub mod mailer;
|
||||||
|
|
Loading…
Reference in a new issue