aboutsummaryrefslogtreecommitdiff
path: root/crates/secd/src/client/email
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--crates/secd/src/client/email.rs67
-rw-r--r--crates/secd/src/client/email/mod.rs68
2 files changed, 68 insertions, 67 deletions
diff --git a/crates/secd/src/client/email.rs b/crates/secd/src/client/email.rs
deleted file mode 100644
index 2712037..0000000
--- a/crates/secd/src/client/email.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use std::{path::PathBuf, str::FromStr};
-
-use email_address::EmailAddress;
-use time::OffsetDateTime;
-
-use super::{
- EmailMessenger, EmailMessengerError, EmailType, EMAIL_TEMPLATE_DEFAULT_LOGIN,
- EMAIL_TEMPLATE_DEFAULT_SIGNUP,
-};
-
-pub(crate) struct LocalEmailStubber {
- pub(crate) email_template_login: Option<String>,
- pub(crate) email_template_signup: Option<String>,
-}
-
-#[async_trait::async_trait]
-impl EmailMessenger for LocalEmailStubber {
- // TODO: this module really shouldn't be called client, it should be called services... the client is sqlx/mailgun/sns wrapper or whatever...
- async fn send_email(
- &self,
- email_address: &str,
- validation_id: &str,
- secret_code: &str,
- t: EmailType,
- ) -> Result<(), EmailMessengerError> {
- let login_template = self
- .email_template_login
- .clone()
- .unwrap_or(EMAIL_TEMPLATE_DEFAULT_LOGIN.to_string());
- let signup_template = self
- .email_template_signup
- .clone()
- .unwrap_or(EMAIL_TEMPLATE_DEFAULT_SIGNUP.to_string());
-
- let replace_template = |s: &str| {
- s.replace(
- "%secd_link%",
- &format!("{}?code={}", validation_id, secret_code),
- )
- .replace("%secd_email_address%", email_address)
- .replace("%secd_code%", secret_code)
- };
-
- if !EmailAddress::is_valid(email_address) {
- return Err(EmailMessengerError::InvalidEmailAddress);
- }
-
- let body = match t {
- EmailType::Login => replace_template(&login_template),
- EmailType::Signup => replace_template(&signup_template),
- };
-
- // TODO: write to the system mailbox instead?
- std::fs::write(
- PathBuf::from_str(&format!(
- "/tmp/{}_{}.localmail",
- OffsetDateTime::now_utc(),
- validation_id
- ))
- .map_err(|_| EmailMessengerError::Unknown)?,
- body,
- )
- .map_err(|_| EmailMessengerError::FailedToSendEmail)?;
-
- Ok(())
- }
-}
diff --git a/crates/secd/src/client/email/mod.rs b/crates/secd/src/client/email/mod.rs
new file mode 100644
index 0000000..915d18c
--- /dev/null
+++ b/crates/secd/src/client/email/mod.rs
@@ -0,0 +1,68 @@
+use email_address::EmailAddress;
+use lettre::Transport;
+use log::error;
+use std::collections::HashMap;
+
+#[derive(Debug, thiserror::Error, derive_more::Display)]
+pub enum EmailMessengerError {
+ FailedToSendEmail,
+}
+
+pub struct EmailValidationMessage {
+ pub recipient: EmailAddress,
+ pub subject: String,
+ pub body: String,
+}
+
+#[async_trait::async_trait]
+pub(crate) trait EmailMessenger {
+ async fn send_email(
+ &self,
+ email_address: &EmailAddress,
+ template: &str,
+ template_vars: HashMap<&str, &str>,
+ ) -> Result<(), EmailMessengerError>;
+}
+
+pub(crate) struct LocalMailer {}
+
+#[async_trait::async_trait]
+impl EmailMessenger for LocalMailer {
+ async fn send_email(
+ &self,
+ email_address: &EmailAddress,
+ template: &str,
+ template_vars: HashMap<&str, &str>,
+ ) -> Result<(), EmailMessengerError> {
+ todo!()
+ }
+}
+
+#[async_trait::async_trait]
+pub(crate) trait Sendable {
+ async fn send(&self) -> Result<(), EmailMessengerError>;
+}
+
+#[async_trait::async_trait]
+impl Sendable for EmailValidationMessage {
+ // TODO: We need to break this up as before, especially so we can feature
+ // gate unwanted things like Lettre...
+ async fn send(&self) -> Result<(), EmailMessengerError> {
+ // TODO: Get these things from the template...
+ let email = lettre::Message::builder()
+ .from("BranchControl <iam@branchcontrol.com>".parse().unwrap())
+ .reply_to("BranchControl <iam@branchcontrol.com>".parse().unwrap())
+ .to(self.recipient.to_string().parse().unwrap())
+ .subject(self.subject.clone())
+ .body(self.body.clone())
+ .unwrap();
+
+ let mailer = lettre::SmtpTransport::unencrypted_localhost();
+
+ mailer.send(&email).map_err(|e| {
+ error!("failed to send email {:?}", e);
+ EmailMessengerError::FailedToSendEmail
+ })?;
+ Ok(())
+ }
+}