From 43080ae92788df957679e5ca327413fbdf193105 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 21 Aug 2025 23:23:32 +0000 Subject: [PATCH 1/2] Improve email sending with TLS support for different SMTP ports Co-authored-by: mescalito911 --- server/api/src/utils/helper.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/server/api/src/utils/helper.rs b/server/api/src/utils/helper.rs index c7cfbb4..ebdf960 100644 --- a/server/api/src/utils/helper.rs +++ b/server/api/src/utils/helper.rs @@ -112,16 +112,30 @@ pub async fn send_email(note: ¬e::Model) -> anyhow::Result { let creds = Credentials::new(user.to_owned(), pass.to_owned()); - // Open a remote connection to gmail - let mailer = SmtpTransport::relay(host.as_str()) - .unwrap() - .credentials(creds) - .port(port.parse::().unwrap()) - .build(); + // Настройка TLS: STARTTLS для 587, implicit TLS (wrapper) для 465 + use lettre::transport::smtp::client::{Tls, TlsParameters}; + let tls_params = TlsParameters::builder(host.clone()).build().unwrap(); + + let mailer = match port.as_str() { + "465" => { + SmtpTransport::relay(host.as_str()) + .unwrap() + .credentials(creds) + .port(465) + .tls(Tls::Wrapper(tls_params)) + .build() + } + _ => { + SmtpTransport::starttls_relay(host.as_str()) + .unwrap() + .credentials(creds) + .port(port.parse::().unwrap()) + .build() + } + }; println!("Sending email to: {}", note.notify_email.as_ref().unwrap()); - // Send the email match mailer.send(&email) { Ok(_) => Ok(true), Err(_) => Ok(false), From dd705781952e664ad8623b100acc36e4607c2059 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 22 Aug 2025 01:44:15 +0000 Subject: [PATCH 2/2] Improve email sending error handling and add more logging in send_email Co-authored-by: mescalito911 --- server/api/src/resource/note.rs | 8 ++- server/api/src/utils/helper.rs | 100 ++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 45 deletions(-) diff --git a/server/api/src/resource/note.rs b/server/api/src/resource/note.rs index db5177c..cf99242 100644 --- a/server/api/src/resource/note.rs +++ b/server/api/src/resource/note.rs @@ -208,7 +208,9 @@ pub async fn get_note( let copy_note = note.clone(); tokio::spawn(async move { - send_email(©_note).await.unwrap(); + if let Err(err) = send_email(©_note).await { + eprintln!("Error while sending email: {}", err); + } }); } } @@ -288,7 +290,9 @@ pub async fn delete_note( ); tokio::spawn(async move { - send_email(¬e).await.unwrap(); + if let Err(err) = send_email(¬e).await { + eprintln!("Error while sending email: {}", err); + } }); } diff --git a/server/api/src/utils/helper.rs b/server/api/src/utils/helper.rs index ebdf960..79d34f1 100644 --- a/server/api/src/utils/helper.rs +++ b/server/api/src/utils/helper.rs @@ -97,47 +97,61 @@ pub async fn check_csrf_token(captcha: CsrfToken, state: &State) -> Op } pub async fn send_email(note: ¬e::Model) -> anyhow::Result { - let host = env::var("SMTP_HOST").expect("SMTP_HOST is not set in .env file"); - let port = env::var("SMTP_PORT").expect("SMTP_PORT is not set in .env file"); - let user = env::var("SMTP_USER").expect("SMTP_USER is not set in .env file"); - let pass = env::var("SMTP_PASS").expect("SMTP_PASS is not set in .env file"); - - let email = Message::builder() - .from(format!("Privnote <{}>", user).parse().unwrap()) - .to(note.notify_email.as_ref().unwrap().parse().unwrap()) - .subject("Your Privnote has been read") - .header(ContentType::TEXT_PLAIN) - .body(format!("privnote has been read: {}", note.id)) - .unwrap(); - - let creds = Credentials::new(user.to_owned(), pass.to_owned()); - - // Настройка TLS: STARTTLS для 587, implicit TLS (wrapper) для 465 - use lettre::transport::smtp::client::{Tls, TlsParameters}; - let tls_params = TlsParameters::builder(host.clone()).build().unwrap(); - - let mailer = match port.as_str() { - "465" => { - SmtpTransport::relay(host.as_str()) - .unwrap() - .credentials(creds) - .port(465) - .tls(Tls::Wrapper(tls_params)) - .build() - } - _ => { - SmtpTransport::starttls_relay(host.as_str()) - .unwrap() - .credentials(creds) - .port(port.parse::().unwrap()) - .build() - } - }; - - println!("Sending email to: {}", note.notify_email.as_ref().unwrap()); - - match mailer.send(&email) { - Ok(_) => Ok(true), - Err(_) => Ok(false), - } + let host = env::var("SMTP_HOST").expect("SMTP_HOST is not set in .env file"); + let port = env::var("SMTP_PORT").expect("SMTP_PORT is not set in .env file"); + let user = env::var("SMTP_USER").expect("SMTP_USER is not set in .env file"); + let pass = env::var("SMTP_PASS").expect("SMTP_PASS is not set in .env file"); + + println!("SMTP Config: {}:{}", host, port); + println!("SMTP User: {}", user); + println!("SMTP Pass length: {}", pass.len()); + + let email = Message::builder() + .from(format!("Privnote <{}>", user).parse().unwrap()) + .to(note.notify_email.as_ref().unwrap().parse().unwrap()) + .subject("Your Privnote has been read") + .header(ContentType::TEXT_PLAIN) + .body(format!("privnote has been read: {}", note.id)) + .unwrap(); + + let creds = Credentials::new(user.to_owned(), pass.to_owned()); + + // Настройка TLS: STARTTLS для 587, implicit TLS (wrapper) для 465 + use lettre::transport::smtp::client::{Tls, TlsParameters}; + let tls_params = TlsParameters::builder(host.clone()).build().unwrap(); + let tls_mode = if port == "465" { "implicit" } else { "starttls" }; + println!("TLS mode: {}", tls_mode); + println!("Building SMTP transport..."); + + let mailer = match port.as_str() { + "465" => { + SmtpTransport::relay(host.as_str()) + .unwrap() + .credentials(creds) + .port(465) + .tls(Tls::Wrapper(tls_params)) + .build() + } + _ => { + SmtpTransport::starttls_relay(host.as_str()) + .unwrap() + .credentials(creds) + .port(port.parse::().unwrap()) + .build() + } + }; + + println!("SMTP transport built successfully"); + println!("Sending email to: {}", note.notify_email.as_ref().unwrap()); + + match mailer.send(&email) { + Ok(_) => { + println!("Email sent successfully"); + Ok(true) + } + Err(e) => { + println!("Failed to send email: {:?}", e); + Err(e.into()) + } + } }