From 2f8dce44d3f2be74b5c6ec0a2e7f4ceced715328 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 13 Jul 2022 10:33:30 +0200 Subject: initial import --- src/mailer.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/mailer.rs (limited to 'src/mailer.rs') diff --git a/src/mailer.rs b/src/mailer.rs new file mode 100644 index 0000000..1ea1a8b --- /dev/null +++ b/src/mailer.rs @@ -0,0 +1,105 @@ +use std::time::Duration; + +use lettre::{ + message::Mailbox, + transport::smtp::client::{Tls, TlsParameters}, + AsyncSmtpTransport, Message, Tokio1Executor, +}; +use rocket::http::uri::Absolute; +use serde_json::json; + +use crate::types::UserID; + +pub struct Mailer { + from: Mailbox, + verify_base: Absolute<'static>, + transport: AsyncSmtpTransport, +} + +impl Mailer { + pub fn new( + from: Mailbox, + host: &str, + port: u16, + verify_base: Absolute<'static>, + ) -> anyhow::Result { + Ok(Mailer { + from, + verify_base, + transport: AsyncSmtpTransport::::builder_dangerous(host) + .port(port) + .tls(Tls::Opportunistic(TlsParameters::new(host.to_string())?)) + .timeout(Some(Duration::from_secs(5))) + .build(), + }) + } + + pub(crate) async fn send_account_verify( + &self, + uid: &UserID, + to: &str, + code: &str, + ) -> anyhow::Result<()> { + let fragment = base64::encode_config( + serde_json::to_string(&json!({ + "uid": uid, + "email": to, + "code": code, + }))?, + base64::URL_SAFE, + ); + let email = Message::builder() + .from(self.from.clone()) + .to(to.parse()?) + .subject("account verify code") + .body(format!("{}/#/verify/{fragment}", self.verify_base))?; + lettre::AsyncTransport::send(&self.transport, email).await?; + Ok(()) + } + + pub(crate) async fn send_session_verify(&self, to: &str, code: &str) -> anyhow::Result<()> { + let email = Message::builder() + .from(self.from.clone()) + .to(to.parse()?) + .subject("session verify code") + .body(format!("{code}"))?; + lettre::AsyncTransport::send(&self.transport, email).await?; + Ok(()) + } + + pub(crate) async fn send_password_changed(&self, to: &str) -> anyhow::Result<()> { + let email = Message::builder() + .from(self.from.clone()) + .to(to.parse()?) + .subject("account password has been changed") + .body(String::from( + "your account password has been changed. if you haven't done this, \ + you're probably in trouble now.", + ))?; + lettre::AsyncTransport::send(&self.transport, email).await?; + Ok(()) + } + + pub(crate) async fn send_password_forgot(&self, to: &str, code: &str) -> anyhow::Result<()> { + let email = Message::builder() + .from(self.from.clone()) + .to(to.parse()?) + .subject("account reset code") + .body(code.to_string())?; + lettre::AsyncTransport::send(&self.transport, email).await?; + Ok(()) + } + + pub(crate) async fn send_account_reset(&self, to: &str) -> anyhow::Result<()> { + let email = Message::builder() + .from(self.from.clone()) + .to(to.parse()?) + .subject("account has been reset") + .body(String::from( + "your account has been reset. if you haven't done this, \ + you're probably in trouble now.", + ))?; + lettre::AsyncTransport::send(&self.transport, email).await?; + Ok(()) + } +} -- cgit v1.2.3