gandi_email/
lib.rs

1use anyhow::Result;
2use reqwest::{header::AUTHORIZATION, Response};
3use serde::{Deserialize, Serialize};
4
5/// Mailbox struct.
6#[derive(Debug, Serialize, Deserialize)]
7pub struct Mailbox {
8    pub address: String,
9    pub id: String,
10    pub alias_count: u32,
11}
12
13#[derive(Debug, Serialize, Deserialize)]
14struct MailboxDetail {
15    aliases: Vec<String>,
16}
17
18/// Instance of API.
19#[derive(Debug)]
20pub struct GandiEmailAPI {
21    api_key: String,
22}
23
24impl GandiEmailAPI {
25    /// Create a new API instance.
26    pub fn new(api_key: String) -> Self {
27        GandiEmailAPI { api_key }
28    }
29
30    async fn get(&self, url: &str) -> Result<Response> {
31        Ok(reqwest::Client::new()
32            .get(format!("https://api.gandi.net/v5{}", url))
33            .header(AUTHORIZATION, format!("Apikey {}", self.api_key))
34            .send()
35            .await?)
36    }
37
38    async fn patch(&self, url: &str, data: &impl Serialize) -> Result<Response> {
39        Ok(reqwest::Client::new()
40            .patch(format!("https://api.gandi.net/v5{}", url))
41            .header(AUTHORIZATION, format!("Apikey {}", self.api_key))
42            .json(data)
43            .send()
44            .await?)
45    }
46
47    /// Get all domains.
48    pub async fn domains(&self) -> Result<Vec<String>> {
49        #[derive(Debug, Serialize, Deserialize)]
50        struct Domain {
51            fqdn: String,
52        }
53
54        let res = self
55            .get("/domain/domains")
56            .await?
57            .json::<Vec<Domain>>()
58            .await?;
59        let res = res.iter().map(|r| r.fqdn.clone()).collect();
60        Ok(res)
61    }
62
63    /// Get all mailboxes.
64    pub async fn mailboxes(&self, domain: &str) -> Result<Vec<Mailbox>> {
65        let res = self
66            .get(&format!("/email/mailboxes/{}", domain))
67            .await?
68            .json::<Vec<Mailbox>>()
69            .await?;
70        Ok(res)
71    }
72
73    /// Get all mailboxes.
74    pub async fn aliases(&self, domain: &str, mailbox_id: &str) -> Result<Vec<String>> {
75        let res = self
76            .get(&format!("/email/mailboxes/{}/{}", domain, mailbox_id))
77            .await?
78            .json::<MailboxDetail>()
79            .await?;
80        Ok(res.aliases)
81    }
82
83    /// Create an alias
84    pub async fn create_alias(&self, domain: &str, mailbox_id: &str, alias: &str) -> Result<()> {
85        let mut aliases = self.aliases(domain, mailbox_id).await?;
86        aliases.push(alias.to_string());
87        let _res = self
88            .patch(
89                &format!("/email/mailboxes/{}/{}", domain, mailbox_id),
90                &MailboxDetail { aliases },
91            )
92            .await?;
93        Ok(())
94    }
95
96    /// Delete an alias
97    pub async fn delete_alias(&self, domain: &str, mailbox_id: &str, alias: &str) -> Result<()> {
98        let mut aliases = self.aliases(domain, mailbox_id).await?;
99        aliases.retain(|e| e != alias);
100        let _res = self
101            .patch(
102                &format!("/email/mailboxes/{}/{}", domain, mailbox_id),
103                &MailboxDetail { aliases },
104            )
105            .await?;
106        Ok(())
107    }
108}