1use std::error::Error;
2
3use scraper::Html;
4use serde_json::{json, Value};
5
6use crate::AccountCredentials;
7
8#[derive(Debug, Clone)]
9pub 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}