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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use reqwest::{
    header::{HeaderMap, HeaderValue},
    Client as HttpClient, StatusCode, Url,
};
use serde::Serialize;
use std::time::Duration;

mod builders;
mod error;
mod types;

use builders::*;
pub use error::Error;
use error::Result;
pub use types::Format;
use types::{Request, Response};

/// A client for the WaffleHacks mailer
#[derive(Debug)]
pub struct Client {
    client: HttpClient,
    base_url: Url,
}

impl Client {
    /// Create a new mailer client
    pub fn new(base_url: Url) -> Self {
        // Create the default headers
        let mut headers = HeaderMap::new();
        headers.insert("Content-Type", HeaderValue::from_static("application/json"));

        // This shouldn't ever return an error
        let client = HttpClient::builder()
            .default_headers(headers)
            .timeout(Duration::from_secs(10))
            .build()
            .unwrap();

        Client { client, base_url }
    }

    /// Send a request to the server
    pub(crate) async fn dispatch<T>(&self, path: &str, req: Request<'_, T>) -> Result<()>
    where
        T: Serialize,
    {
        let resp = self
            .client
            .post(self.base_url.join(path).unwrap())
            .json(&req)
            .send()
            .await?;

        let status = resp.status();
        if status == StatusCode::OK {
            Ok(())
        } else {
            let body: Response = resp.json().await?;
            if status == StatusCode::BAD_REQUEST {
                Err(Error::InvalidArgument(body.message))
            } else {
                Err(Error::Unknown(body.message))
            }
        }
    }

    /// Send a single email
    pub async fn send<'s>(
        &'s self,
        to: &'s str,
        from: &'s str,
        subject: &'s str,
        body: &'s str,
    ) -> SendBuilder<'s> {
        SendBuilder::new(self, to, from, subject, body)
    }

    /// Send an email to many recipients
    pub async fn send_batch<'s>(
        &'s self,
        from: &'s str,
        subject: &'s str,
        body: &'s str,
    ) -> SendBatchBuilder<'s> {
        SendBatchBuilder::new(self, from, subject, body)
    }

    /// Send a templated email to many recipients
    pub async fn send_template<'s>(
        &'s self,
        from: &'s str,
        subject: &'s str,
        body: &'s str,
    ) -> SendTemplateBuilder<'s> {
        SendTemplateBuilder::new(self, from, subject, body)
    }
}