rss2email_lib/email/
sendgrid.rs

1//! [`EmailProvider`] implementation using [`SendGrid`](https://sendgrid.com/).
2
3use itertools::Itertools;
4
5use crate::info;
6
7use super::{email_provider::EmailProvider, error::EmailError, EnvLoader};
8
9#[derive(Default, Debug)]
10pub struct SendGrid {
11  api_key: Option<String>,
12}
13
14impl SendGrid {
15  pub(crate) fn new(env_loader: &EnvLoader) -> Self {
16    Self {
17      api_key: env_loader.api_key.clone(),
18    }
19  }
20}
21
22impl EmailProvider for SendGrid {
23  fn send_email(
24    &self,
25    from_address: &str,
26    recipient_addresses: Vec<&str>,
27    subject: &str,
28    contents: &str,
29  ) -> Result<(), EmailError> {
30    let api_key = self
31      .api_key
32      .as_ref()
33      .ok_or_else(|| EmailError::Config("Cannot use SendGrid without API_KEY".to_owned()))?;
34
35    let personalizations = recipient_addresses
36      .iter()
37      .map(|address| format!(r#"{{"to": [{{"email": "{address}"}}]}}"#))
38      .join(",");
39
40    let message = format!(
41      r#"{{"personalizations": [{personalizations}],"from": {{"email": "{from_address}"}},"subject": "{subject}","content": [{{"type": "text/html", "value": "{contents}"}}]}}"#
42    );
43
44    let http_client = reqwest::blocking::Client::new();
45    let req = http_client
46      .post("https://api.sendgrid.com/v3/mail/send")
47      .header("Authorization", &format!("Bearer {api_key}"))
48      .header("Content-Type", "application/json")
49      .body(message)
50      .build()?;
51    let response = http_client.execute(req);
52
53    match response {
54      Ok(response) => {
55        info!("Email request sent with {}", response.status().as_str());
56        Ok(())
57      }
58      Err(e) => Err(e.into()),
59    }
60  }
61}