spacetimedb/
sendgrid_controller.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use sendgrid::v3::{Email, Personalization, SGMap};

#[derive(Clone)]
pub struct SendGridController {
    sender: sendgrid::v3::Sender,
    sendgrid_sender: Email,
}

const AUTH_URL: &str = "https://spacetimedb.net/auth";

impl SendGridController {
    /// Get a SendGridController, pulling from environment variables, returning None if the env vars aren't present.
    pub fn new() -> Option<Self> {
        match (std::env::var("SENDGRID_API_KEY"), std::env::var("SENDGRID_SENDER")) {
            (Ok(api_key), Ok(sendgrid_sender)) => Some(SendGridController {
                sender: sendgrid::v3::Sender::new(api_key),
                sendgrid_sender: Email::new(sendgrid_sender),
            }),
            _ => {
                log::warn!("SENDGRID_API_KEY or SENDGRID_SENDER env variables not set, SendGrid is disabled.");
                None
            }
        }
    }

    /// # Description
    ///
    /// Sends a recovery email to the provided `email` address.
    ///
    /// # Arguments
    ///  * `email` - The email to send the recovery email to
    ///  * `code` - The recovery code to send
    ///  * `identity` - The identity the user is trying to recover
    ///  * `link` - Whether or not this request originated from the website. Typically if a user is
    ///               attempting to login to the website, we will send them a link to click on instead
    ///               of giving them a recovery code.
    pub async fn send_recovery_email(
        &self,
        email: &str,
        code: &str,
        identity: &str,
        link: bool,
    ) -> Result<(), anyhow::Error> {
        let mut data = SGMap::new();
        data.insert(
            "link".to_string(),
            if link {
                url::Url::parse_with_params(AUTH_URL, [("email", email), ("code", code), ("identity", identity)])
                    .unwrap()
                    .into()
            } else {
                format!("Your recovery code: {}", code)
            },
        );
        let personalization = Personalization::new(Email::new(email));
        let message = sendgrid::v3::Message::new(self.sendgrid_sender.clone())
            .set_subject("Login to SpacetimeDB")
            .set_template_id("d-70a7cea2bf8941a5909919fcf904d687")
            .add_personalization(personalization.add_dynamic_template_data(data));
        self.sender.send(&message).await?;
        Ok(())
    }
}