Skip to main content

email_clients/clients/
mailersend.rs

1use crate::configuration::EmailConfiguration;
2use crate::email::{EmailAddress, EmailObject};
3use crate::traits::EmailTrait;
4use crate::Result;
5use async_trait::async_trait;
6use reqwest::header::HeaderMap;
7use reqwest::{header, Client, Method};
8use secrecy::{ExposeSecret, Secret};
9
10static BASE_URL: &str = "https://api.mailersend.com/v1";
11
12fn default_base_url() -> String {
13    BASE_URL.to_string()
14}
15
16/// `MailerSendConfig` structure that includes sender, base_url, and api_token.
17///
18/// ```rust
19/// use email_clients::clients::mailersend::MailerSendConfig;
20///
21/// let mut mailer_send_config = MailerSendConfig::default()
22///                                .sender("sender@example.com")
23///                                .base_url("https://api.mailersend.com/v1")
24///                                .api_token("test_api_token");
25/// assert_eq!(mailer_send_config.get_sender().to_string(), "sender@example.com");
26/// assert_eq!(mailer_send_config.get_base_url(), "https://api.mailersend.com/v1");
27/// ```
28#[derive(Debug, Clone, serde::Deserialize)]
29pub struct MailerSendConfig {
30    sender: EmailAddress,
31    #[serde(default = "default_base_url")]
32    base_url: String,
33    api_token: Secret<String>,
34}
35
36#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
37struct EmailPayload {
38    from: EmailAddress,
39    to: Vec<EmailAddress>,
40    subject: String,
41    text: String,
42    html: String,
43}
44
45impl From<EmailObject> for EmailPayload {
46    fn from(value: EmailObject) -> Self {
47        Self {
48            from: value.sender,
49            to: value.to,
50            subject: value.subject,
51            text: value.plain,
52            html: value.html,
53        }
54    }
55}
56
57impl Default for MailerSendConfig {
58    /// Constructs a `MailerSendConfig` with default values:
59    /// - sender: An empty string `""`
60    /// - base_url: `https://api.mailersend.com/v1`
61    /// - api_token: An empty string `""`
62    ///
63    /// # Examples
64    ///
65    /// Basic usage:
66    ///
67    /// ```rust
68    /// use email_clients::clients::mailersend::MailerSendConfig;
69    ///
70    /// let config = MailerSendConfig::default();
71    ///
72    /// assert_eq!(config.get_sender().to_string(), "");
73    /// assert_eq!(config.get_base_url(), "https://api.mailersend.com/v1");
74    /// ```
75    ///
76    fn default() -> Self {
77        Self {
78            sender: "".into(),
79            base_url: BASE_URL.to_string(),
80            api_token: Secret::from("".to_string()),
81        }
82    }
83}
84
85impl MailerSendConfig {
86    /// Sets the sender of the Mailersend config.
87    ///
88    /// ```rust
89    /// use email_clients::clients::mailersend::MailerSendConfig;
90    ///
91    /// let mut smtp_config = MailerSendConfig::default().sender("Test Sender");
92    /// assert_eq!(smtp_config.get_sender().to_string(), "Test Sender");
93    /// ```
94    pub fn sender(mut self, value: impl Into<EmailAddress>) -> Self {
95        self.sender = value.into();
96        self
97    }
98
99    /// Sets the base_url of the Mailersend config.
100    ///
101    /// ```rust
102    /// use email_clients::clients::mailersend::MailerSendConfig;
103    ///
104    /// let mut smtp_config = MailerSendConfig::default().base_url("Test URL");
105    /// assert_eq!(smtp_config.get_base_url(), "Test URL");
106    /// ```
107    pub fn base_url(mut self, value: impl AsRef<str>) -> Self {
108        self.base_url = value.as_ref().trim_end_matches('/').to_string();
109        self
110    }
111
112    /// Sets the api_token of the Mailersend config.
113    ///
114    /// ```rust
115    /// use email_clients::clients::mailersend::MailerSendConfig;
116    ///
117    /// let mut smtp_config = MailerSendConfig::default().api_token("Test Token");
118    /// ```
119    pub fn api_token(mut self, value: impl AsRef<str>) -> Self {
120        self.api_token = Secret::new(value.as_ref().to_string());
121        self
122    }
123
124    /// Returns the base url of the Mailersend config.
125    ///
126    /// # Example
127    ///
128    /// ```rust
129    /// use email_clients::clients::mailersend::MailerSendConfig;
130    ///
131    /// let smtp_config = MailerSendConfig::default().base_url("https://api.mailersend.com/v1");
132    /// assert_eq!(smtp_config.get_base_url(), "https://api.mailersend.com/v1");
133    /// ```
134    ///
135    pub fn get_base_url(&self) -> String {
136        self.base_url.to_string()
137    }
138
139    /// Returns the sender of the Mailersend config.
140    ///
141    /// # Example
142    ///
143    /// ```rust
144    /// use email_clients::clients::mailersend::MailerSendConfig;
145    ///
146    /// let mailer_send_config = MailerSendConfig::default().sender("test_sender@example.com");
147    /// assert_eq!(mailer_send_config.get_sender().to_string(), "test_sender@example.com");
148    /// ```
149    ///
150    pub fn get_sender(&self) -> EmailAddress {
151        self.sender.clone()
152    }
153}
154
155impl From<MailerSendConfig> for EmailConfiguration {
156    /// Converts a `MailerSendConfig` into an `EmailConfiguration`
157    ///
158    /// This conversion is mainly used when we are setting the configuration for our email client.
159    ///
160    /// # Example
161    ///
162    /// ```rust
163    /// use email_clients::clients::mailersend::MailerSendConfig;
164    /// use email_clients::configuration::EmailConfiguration;
165    ///
166    /// let mailer_config = MailerSendConfig::default()
167    ///                 .sender("sender@example.com")
168    ///                 .base_url("https://api.mailersend.com/v1")
169    ///                 .api_token("test_api_token");
170    ///
171    /// let email_config: EmailConfiguration = mailer_config.into();
172    /// ```
173    fn from(value: MailerSendConfig) -> Self {
174        EmailConfiguration::Mailersend(value)
175    }
176}
177
178/// `MailerSendClient` structure that includes 'config' and 'reqwest_client'.
179///
180/// ```rust
181/// use email_clients::clients::mailersend::MailerSendConfig;
182/// use email_clients::clients::mailersend::MailerSendClient;
183///
184/// let mailer_send_config = MailerSendConfig::default()
185///                            .sender("sender@example.com")
186///                            .base_url("https://api.mailersend.com/v1")
187///                            .api_token("test_api_token");
188/// let mailer_send_client = MailerSendClient::new(mailer_send_config);
189/// ```
190#[derive(Clone, Debug, Default)]
191pub struct MailerSendClient {
192    config: MailerSendConfig,
193    reqwest_client: Client,
194}
195
196impl MailerSendClient {
197    pub fn new(config: MailerSendConfig) -> Self {
198        let reqwest_client = Client::new();
199
200        MailerSendClient {
201            config,
202            reqwest_client,
203        }
204    }
205
206    fn url(&self) -> String {
207        format!("{}/email", self.config.base_url.trim_end_matches('/'))
208    }
209
210    fn headers(&self) -> Result<HeaderMap> {
211        let mut headers = HeaderMap::new();
212        headers.insert(
213            header::AUTHORIZATION,
214            format!("Bearer {}", self.config.api_token.expose_secret()).parse()?,
215        );
216        Ok(headers)
217    }
218}
219
220#[async_trait]
221impl EmailTrait for MailerSendClient {
222    /// Returns the sender included in the `MailerSendClient`'s configuration.
223    ///
224    /// # Examples
225    ///
226    /// Basic usage:
227    ///
228    /// ```rust
229    /// use email_clients::clients::mailersend::MailerSendConfig;
230    /// use email_clients::clients::mailersend::MailerSendClient;
231    /// use email_clients::traits::EmailTrait;
232    ///
233    /// let mailer_send_config = MailerSendConfig::default()
234    ///     .sender("sender@example.com")
235    ///     .base_url("https://api.mailersend.com/v1")
236    ///     .api_token("test_api_token");
237    ///
238    /// let mailer_send_client = MailerSendClient::new(mailer_send_config);
239    ///
240    /// assert_eq!(mailer_send_client.get_sender().to_string(), "sender@example.com");
241    /// ```
242    fn get_sender(&self) -> EmailAddress {
243        self.config.get_sender().clone()
244    }
245
246    async fn send_emails(&self, email: EmailObject) -> Result<()> {
247        let payload: EmailPayload = email.into();
248        self.reqwest_client
249            .request(Method::POST, self.url())
250            .headers(self.headers()?)
251            .json(&payload)
252            .send()
253            .await?
254            .error_for_status()?;
255        Ok(())
256    }
257}