mailtm_client/
client.rs

1use std::error::Error;
2
3use scraper::Html;
4use serde_json::{json, Value};
5
6use crate::AccountCredentials;
7
8#[derive(Debug, Clone)]
9/// Client for https://mail.tm/
10pub struct Client {
11    pub client: reqwest::Client,
12    pub account_id: String,
13    token: String,
14    pub email_address: String,
15}
16
17impl Client {
18    pub async fn new(account_credentials: &AccountCredentials) -> Result<Self, Box<dyn Error>> {
19        let client = reqwest::Client::new();
20
21        let domains = Self::get_domains().await?;
22        let domain = &domains[0];
23        let address = format!("{}@{}", account_credentials.username, domain);
24
25        let email_address = client
26            .post("https://api.mail.tm/accounts")
27            .header("Content-Type", "application/json")
28            .body(
29                json!({"address": address, "password": account_credentials.password }).to_string(),
30            )
31            .send()
32            .await?
33            .json::<Value>()
34            .await?["address"]
35            .as_str()
36            .unwrap()
37            .to_string();
38
39        let auth_response = client
40            .post("https://api.mail.tm/token")
41            .header("Content-Type", "application/json")
42            .body(
43                json!({"address": email_address, "password": account_credentials.password })
44                    .to_string(),
45            )
46            .send()
47            .await?
48            .json::<Value>()
49            .await?;
50
51        let (token, account_id) = (
52            auth_response["token"].as_str().unwrap().to_string(),
53            auth_response["id"].as_str().unwrap().to_string(),
54        );
55
56        Ok(Self {
57            client,
58            account_id,
59            token,
60            email_address,
61        })
62    }
63
64    pub async fn request_latest_message_html(&self) -> Result<Option<Html>, Box<dyn Error>> {
65        let response = self
66            .client
67            .get("https://api.mail.tm/messages")
68            .bearer_auth(&self.token)
69            .send()
70            .await?;
71
72        if let Some(content_length) = response.content_length() {
73            if content_length == 0 {
74                return Ok(None);
75            }
76        }
77
78        let messages: Vec<String> = response
79            .json::<Value>()
80            .await?
81            .get("hydra:member")
82            .unwrap()
83            .as_array()
84            .unwrap()
85            .iter()
86            .map(|v| v.get("id").unwrap().as_str().unwrap().to_string())
87            .collect();
88
89        if messages.is_empty() {
90            return Ok(None);
91        }
92
93        let message_id = messages.first().unwrap();
94
95        let response = self
96            .client
97            .get(format!("https://api.mail.tm/messages/{}", message_id))
98            .bearer_auth(&self.token)
99            .send()
100            .await?;
101
102        if let Some(content_length) = response.content_length() {
103            if content_length == 0 {
104                return Ok(None);
105            }
106        }
107
108        let html_string = response
109            .json::<Value>()
110            .await?
111            .get("html")
112            .unwrap()
113            .as_array()
114            .unwrap()
115            .first()
116            .unwrap()
117            .as_str()
118            .unwrap()
119            .to_string();
120
121        self.client
122            .delete(format!("https://api.mail.tm/messages/{}", message_id))
123            .bearer_auth(&self.token)
124            .send()
125            .await?;
126
127        let html = Html::parse_document(&html_string);
128
129        return Ok(Some(html));
130    }
131
132    pub async fn delete(&self) -> Result<(), Box<dyn Error>> {
133        self.client
134            .delete(format!("https://api.mail.tm/token/{}", self.account_id))
135            .bearer_auth(&self.token)
136            .send()
137            .await?;
138
139        Ok(())
140    }
141
142    pub async fn get_domains() -> Result<Vec<String>, Box<dyn Error>> {
143        Ok(reqwest::get("https://api.mail.tm/domains")
144            .await?
145            .json::<Value>()
146            .await?["hydra:member"]
147            .as_array()
148            .unwrap()
149            .iter()
150            .map(|v| v["domain"].as_str().unwrap().to_string())
151            .collect())
152    }
153}