From 4b2eb1b1ba9ef1590e651636835fe3fdd7d0b5c1 Mon Sep 17 00:00:00 2001 From: Zack Fu Zi Xiang Date: Thu, 14 Nov 2024 16:00:15 +0800 Subject: [PATCH] feat: separate smtp username from email --- deploy.env | 1 + dev.env | 1 + libs/mailer/src/config.rs | 1 + libs/mailer/src/sender.rs | 12 +++++++----- services/appflowy-worker/src/application.rs | 3 ++- services/appflowy-worker/src/config.rs | 6 ++++++ services/appflowy-worker/src/mailer.rs | 5 +++-- src/application.rs | 3 ++- src/config/config.rs | 1 + 9 files changed, 24 insertions(+), 9 deletions(-) diff --git a/deploy.env b/deploy.env index b021f8034..c1799af87 100644 --- a/deploy.env +++ b/deploy.env @@ -113,6 +113,7 @@ APPFLOWY_S3_BUCKET=appflowy APPFLOWY_MAILER_SMTP_HOST=smtp.gmail.com APPFLOWY_MAILER_SMTP_PORT=465 APPFLOWY_MAILER_SMTP_USERNAME=email_sender@some_company.com +APPFLOWY_MAILER_SMTP_EMAIL=email_sender@some_company.com APPFLOWY_MAILER_SMTP_PASSWORD=email_sender_password # Log level for the appflowy-cloud service diff --git a/dev.env b/dev.env index 8ab1eff2b..8832a3721 100644 --- a/dev.env +++ b/dev.env @@ -88,6 +88,7 @@ APPFLOWY_S3_BUCKET=appflowy # Note that smtps (TLS) is always required, even for ports other than 465 APPFLOWY_MAILER_SMTP_HOST=smtp.gmail.com APPFLOWY_MAILER_SMTP_USERNAME=notify@appflowy.io +APPFLOWY_MAILER_SMTP_EMAIL=notify@appflowy.io APPFLOWY_MAILER_SMTP_PASSWORD=email_sender_password RUST_LOG=info diff --git a/libs/mailer/src/config.rs b/libs/mailer/src/config.rs index 71acd8bee..9f0631998 100644 --- a/libs/mailer/src/config.rs +++ b/libs/mailer/src/config.rs @@ -5,5 +5,6 @@ pub struct MailerSetting { pub smtp_host: String, pub smtp_port: u16, pub smtp_username: String, + pub smtp_email: String, pub smtp_password: Secret, } diff --git a/libs/mailer/src/sender.rs b/libs/mailer/src/sender.rs index 14d51c132..13564f8e3 100644 --- a/libs/mailer/src/sender.rs +++ b/libs/mailer/src/sender.rs @@ -5,21 +5,23 @@ use lettre::transport::smtp::authentication::Credentials; use lettre::Address; use lettre::AsyncSmtpTransport; use lettre::AsyncTransport; +use secrecy::ExposeSecret; #[derive(Clone)] pub struct Mailer { smtp_transport: AsyncSmtpTransport, - smtp_username: String, + smtp_email: String, handlers: Handlebars<'static>, } impl Mailer { pub async fn new( smtp_username: String, - smtp_password: String, + smtp_email: String, + smtp_password: secrecy::Secret, smtp_host: &str, smtp_port: u16, ) -> Result { - let creds = Credentials::new(smtp_username.clone(), smtp_password); + let creds = Credentials::new(smtp_username, smtp_password.expose_secret().to_string()); let smtp_transport = AsyncSmtpTransport::::relay(smtp_host)? .credentials(creds) .port(smtp_port) @@ -27,7 +29,7 @@ impl Mailer { let handlers = Handlebars::new(); Ok(Self { smtp_transport, - smtp_username, + smtp_email, handlers, }) } @@ -64,7 +66,7 @@ impl Mailer { let email = Message::builder() .from(lettre::message::Mailbox::new( Some("AppFlowy Notification".to_string()), - self.smtp_username.parse::
()?, + self.smtp_email.parse::
()?, )) .to(lettre::message::Mailbox::new( recipient_name, diff --git a/services/appflowy-worker/src/application.rs b/services/appflowy-worker/src/application.rs index 0617d911b..55cc2106c 100644 --- a/services/appflowy-worker/src/application.rs +++ b/services/appflowy-worker/src/application.rs @@ -145,7 +145,8 @@ pub struct AppState { async fn get_worker_mailer(config: &Config) -> Result { let mailer = Mailer::new( config.mailer.smtp_username.clone(), - config.mailer.smtp_password.expose_secret().clone(), + config.mailer.smtp_email.clone(), + config.mailer.smtp_password.clone(), &config.mailer.smtp_host, config.mailer.smtp_port, ) diff --git a/services/appflowy-worker/src/config.rs b/services/appflowy-worker/src/config.rs index a5bcea03e..21282e43b 100644 --- a/services/appflowy-worker/src/config.rs +++ b/services/appflowy-worker/src/config.rs @@ -48,6 +48,12 @@ impl Config { mailer: MailerSetting { smtp_host: get_env_var("APPFLOWY_MAILER_SMTP_HOST", "smtp.gmail.com"), smtp_port: get_env_var("APPFLOWY_MAILER_SMTP_PORT", "465").parse()?, + smtp_email: get_env_var("APPFLOWY_MAILER_SMTP_EMAIL", "sender@example.com"), + // `smtp_username` could be the same as `smtp_email`, but may not have to be. + // For example: + // - Azure Communication services uses a string of the format .. + // - SendGrid uses the string apikey + // Adapted from: https://github.com/AppFlowy-IO/AppFlowy-Cloud/issues/984 smtp_username: get_env_var("APPFLOWY_MAILER_SMTP_USERNAME", "sender@example.com"), smtp_password: get_env_var("APPFLOWY_MAILER_SMTP_PASSWORD", "password").into(), }, diff --git a/services/appflowy-worker/src/mailer.rs b/services/appflowy-worker/src/mailer.rs index 5c448778b..db362085b 100644 --- a/services/appflowy-worker/src/mailer.rs +++ b/services/appflowy-worker/src/mailer.rs @@ -58,8 +58,9 @@ mod tests { #[tokio::test] async fn render_import_report() { let mailer = Mailer::new( - "test mailer".to_string(), - "123".to_string(), + "smtp_username".to_string(), + "stmp_email".to_string(), + "smtp_password".to_string().into(), "localhost", 465, ) diff --git a/src/application.rs b/src/application.rs index 6741dee38..311f2c82a 100644 --- a/src/application.rs +++ b/src/application.rs @@ -511,7 +511,8 @@ async fn create_bucket_if_not_exists( async fn get_mailer(config: &Config) -> Result { let mailer = Mailer::new( config.mailer.smtp_username.clone(), - config.mailer.smtp_password.expose_secret().clone(), + config.mailer.smtp_email.clone(), + config.mailer.smtp_password.clone(), &config.mailer.smtp_host, config.mailer.smtp_port, ) diff --git a/src/config/config.rs b/src/config/config.rs index 79c5d2814..419e447fc 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -261,6 +261,7 @@ pub fn get_configuration() -> Result { smtp_host: get_env_var("APPFLOWY_MAILER_SMTP_HOST", "smtp.gmail.com"), smtp_port: get_env_var("APPFLOWY_MAILER_SMTP_PORT", "465").parse()?, smtp_username: get_env_var("APPFLOWY_MAILER_SMTP_USERNAME", "sender@example.com"), + smtp_email: get_env_var("APPFLOWY_MAILER_SMTP_EMAIL", "sender@example.com"), smtp_password: get_env_var("APPFLOWY_MAILER_SMTP_PASSWORD", "password").into(), }, apple_oauth: AppleOAuthSetting {