summaryrefslogtreecommitdiff
path: root/src/mailer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailer.rs')
-rw-r--r--src/mailer.rs105
1 files changed, 105 insertions, 0 deletions
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<Tokio1Executor>,
+}
+
+impl Mailer {
+ pub fn new(
+ from: Mailbox,
+ host: &str,
+ port: u16,
+ verify_base: Absolute<'static>,
+ ) -> anyhow::Result<Self> {
+ Ok(Mailer {
+ from,
+ verify_base,
+ transport: AsyncSmtpTransport::<Tokio1Executor>::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(())
+ }
+}