resend_email/
client.rs

1use crate::error::Error;
2use serde::{Deserialize, Serialize};
3
4const API_URL: &str = "https://api.resend.com/emails";
5
6#[derive(Debug, Deserialize)]
7pub struct Email {
8    pub id: String,
9}
10pub struct ResendClient<'a> {
11    auth_token: &'a str,
12}
13
14impl<'a> ResendClient<'a> {
15    pub fn new(auth_token: &'a str) -> Self {
16        ResendClient { auth_token }
17    }
18
19    pub async fn send(&self, mail: &impl Serialize) -> Result<Email, Error> {
20        let resp = reqwest::Client::new()
21            .post(API_URL)
22            .bearer_auth(self.auth_token)
23            .header(reqwest::header::CONTENT_TYPE, "application/json")
24            .json(mail)
25            .send()
26            .await
27            .unwrap();
28
29        match resp.status().is_success() {
30            true => {
31                let email: Email = resp.json().await.unwrap();
32                Ok(email)
33            }
34            false => Err(Error::ResendError(resp.text().await.unwrap())),
35        }
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::super::mail::{Attachment, MailHtml, MailText};
42    use super::ResendClient;
43    use dotenv::dotenv;
44    use std::env;
45    use tokio;
46
47    struct Credentials {
48        auth_token: String,
49        test_email: String,
50    }
51
52    fn get_credentials() -> Credentials {
53        dotenv().ok();
54        let auth_token = env::var("AUTH_TOKEN").unwrap();
55        let test_email = env::var("TEST_EMAIL").unwrap();
56
57        Credentials {
58            auth_token,
59            test_email,
60        }
61    }
62
63    #[tokio::test]
64    async fn send_mail_text() {
65        let credentials = get_credentials();
66        let mail = MailText {
67            from: "Acme <onboarding@resend.dev>",
68            to: vec![&credentials.test_email],
69            subject: "a",
70            text: "a",
71            attachments: None,
72        };
73
74        let client = ResendClient::new(&credentials.auth_token);
75        let resp = client.send(&mail).await.unwrap();
76        println!("{:?}", resp);
77    }
78
79    #[tokio::test]
80    async fn send_mail_html() {
81        let credentials = get_credentials();
82        let mail = MailHtml {
83            from: "Acme <onboarding@resend.dev>",
84            to: vec![&credentials.test_email],
85            subject: "a",
86            html: "<p>hola</p>",
87            attachments: None,
88        };
89
90        let client = ResendClient::new(&credentials.auth_token);
91        let resp = client.send(&mail).await.unwrap();
92        println!("{:?}", resp);
93    }
94
95    #[test]
96    fn format() {
97        let mail = MailText {
98            from: "a",
99            to: vec!["a"],
100            subject: "a",
101            text: "a",
102            attachments: None,
103        };
104
105        assert_eq!(
106            serde_json::to_string(&mail).unwrap(),
107            r#"{"from":"a","to":["a"],"subject":"a","text":"a","attachments":null}"#
108        );
109    }
110
111    #[test]
112    fn format_attachment() {
113        let image = Attachment {
114            content: vec![],
115            filename: "image.png",
116        };
117
118        let mail = MailText {
119            from: "a",
120            to: vec!["a"],
121            subject: "a",
122            text: "a",
123            attachments: Some(vec![image]),
124        };
125
126        assert_eq!(
127            serde_json::to_string(&mail).unwrap(),
128            r#"{"from":"a","to":["a"],"subject":"a","text":"a","attachments":[{"content":[],"filename":"image.png"}]}"#
129        );
130    }
131}