br_email/
lib.rs

1use std::collections::BTreeMap;
2use std::{fs, io};
3use std::io::Error;
4use std::path::PathBuf;
5use serde::{Deserialize, Serialize};
6use crate::analyze::AnalyzeEmails;
7#[cfg(feature = "imap")]
8use crate::imap::Imap;
9#[cfg(feature = "pop3")]
10use crate::pop3::Pop3;
11#[cfg(feature = "smtp")]
12use crate::smtp::Smtp;
13
14#[cfg(feature = "pop3")]
15mod pop3;
16#[cfg(feature = "imap")]
17mod imap;
18#[cfg(feature = "smtp")]
19mod smtp;
20
21pub mod analyze;
22pub mod pools;
23
24#[derive(Clone, Debug)]
25pub struct Mail {
26    /// 协议
27    protocol: Protocol,
28    /// 邮件地址
29    host: String,
30    /// 邮件端口
31    port: u16,
32    /// 邮件名称
33    name: String,
34    /// 邮件账号
35    mail: String,
36    /// 邮件密码
37    pass: String,
38    /// 邮件类型
39    email_type: EmailType,
40}
41
42impl Mail {
43    pub fn new_new(config: Config) -> Result<Self, String> {
44        let connection = config.connections.get(&*config.default).unwrap().clone();
45        Ok(Self {
46            protocol: connection.protocol,
47            host: connection.host,
48            port: connection.port,
49            name: connection.name,
50            mail: connection.mail,
51            pass: connection.pass,
52            email_type: connection.email_type,
53        })
54    }
55    pub fn new(protocol: &str, host: &str, port: u16, name: &str, mail: &str, pass: &str) -> Self {
56        Self {
57            protocol: Protocol::from(protocol),
58            host: host.to_string(),
59            port,
60            name: name.to_string(),
61            mail: mail.to_string(),
62            pass: pass.to_string(),
63            email_type: EmailType::from(mail),
64        }
65    }
66    /// 解析邮件
67    pub fn analyze(data: Vec<u8>, debug: bool) -> io::Result<AnalyzeEmails> {
68        AnalyzeEmails::new(data, debug)
69    }
70    /// 接收
71    pub fn receive(&mut self) -> Box<dyn Receive> {
72        match self.protocol {
73            #[cfg(feature = "pop3")]
74            Protocol::POP3 => Box::new(Pop3::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
75            #[cfg(feature = "smtp")]
76            Protocol::Smtp => Box::new(Smtp::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
77            #[cfg(feature = "imap")]
78            Protocol::Imap => Box::new(Imap::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
79            _ => todo!()
80        }
81    }
82    /// 发送
83    pub fn sender(&mut self) -> Box<dyn Sender> {
84        match self.protocol {
85            #[cfg(feature = "pop3")]
86            Protocol::POP3 => Box::new(Pop3::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
87            #[cfg(feature = "smtp")]
88            Protocol::Smtp => Box::new(Smtp::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
89            #[cfg(feature = "imap")]
90            Protocol::Imap => Box::new(Imap::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
91            _ => todo!()
92        }
93    }
94}
95
96pub trait Receive {
97    /// 获取邮件总数
98    fn get_total(&mut self) -> Result<usize, Error>;
99    /// 获取指定量ID列表
100    fn get_id_list(&mut self) -> Result<Vec<String>, Error>;
101    /// 获取指定ID邮件
102    /// 返回 (邮件内容,邮件尺寸,邮件指纹)
103    fn get_id_info(&mut self, id: &str) -> Result<(Vec<u8>, usize, String), Error>;
104    /// 删除指定邮件
105    fn del_id(&mut self, id: &str) -> Result<bool, Error>;
106}
107
108pub trait Sender {
109    /// 发送邮件
110    /// 返回 (邮件内容,邮件尺寸,邮件指纹)
111    fn send(&mut self) -> Result<(Vec<u8>, usize, String), Error>;
112
113    /// 设置发件人信息
114    /// * name 发件人名称
115    /// * mail 发件箱
116    fn set_from(&mut self, name: &str) -> &mut dyn Sender;
117
118    /// 收件人
119    /// * name 收件人名称
120    /// * mail 收件箱
121    fn set_to(&mut self, name: &str, mail: &str) -> &mut dyn Sender;
122    /// 抄送人
123    /// * name 抄送人名称
124    /// * mail 收件箱
125    fn set_cc(&mut self, name: &str, mail: &str) -> &mut dyn Sender;
126    /// 设置主题
127    fn set_subject(&mut self, subject: &str) -> &mut dyn Sender;
128    /// 设置内容
129    fn set_body(&mut self, text: &str, html: &str) -> &mut dyn Sender;
130    /// 设置文件
131    fn set_file(&mut self, name: &str, data: Vec<u8>, content_type: &str) -> &mut dyn Sender;
132}
133
134#[derive(Clone, Debug, Deserialize, Serialize)]
135enum Protocol {
136    POP3,
137    Smtp,
138    Imap,
139    None,
140}
141
142impl Protocol {
143    pub fn from(name: &str) -> Self {
144        let name = name.to_lowercase();
145        match name.as_str() {
146            "pop3" => Protocol::POP3,
147            "imap" => Protocol::Imap,
148            "smtp" => Protocol::Smtp,
149            _ => Protocol::None,
150        }
151    }
152}
153
154#[derive(Clone, Debug, Deserialize, Serialize)]
155enum EmailType {
156    Google,
157    Qq,
158    None,
159}
160impl EmailType {
161    pub fn from(email: &str) -> Self {
162        match email {
163            x if x.contains("@gmail.com") => EmailType::Google,
164            x if x.contains("@qq.com") => EmailType::Qq,
165            _ => EmailType::None,
166        }
167    }
168}
169
170#[derive(Clone, Debug, Deserialize, Serialize)]
171pub struct Config {
172    default: String,
173    connections: BTreeMap<String, Connection>,
174}
175impl Default for Config {
176    fn default() -> Self {
177        Self::new()
178    }
179}
180
181impl Config {
182    pub fn create(config_file: PathBuf, pkg_name: bool) -> Config {
183        #[derive(Clone, Debug, Deserialize, Serialize)]
184        pub struct ConfigNew {
185            pub br_email: Config,
186        }
187        impl ConfigNew {
188            pub fn new() -> ConfigNew {
189                let mut connections = BTreeMap::new();
190                connections.insert("my_name".to_string(), Connection::default());
191                Self {
192                    br_email: Config {
193                        default: "my_name".to_string(),
194                        connections,
195                    },
196                }
197            }
198        }
199        match fs::read_to_string(config_file.clone()) {
200            Ok(e) => {
201                if pkg_name {
202                    let data = ConfigNew::new();
203                    toml::from_str::<ConfigNew>(&e).unwrap_or_else(|_| {
204                        let toml = toml::to_string(&data).unwrap();
205                        let toml = format!("{e}\r\n{toml}");
206                        let _ = fs::write(config_file.to_str().unwrap(), toml);
207                        data
208                    }).br_email
209                } else {
210                    let data = Config::new();
211                    toml::from_str::<Config>(&e).unwrap_or_else(|_| {
212                        let toml = toml::to_string(&data).unwrap();
213                        let toml = format!("{e}\r\n{toml}");
214                        let _ = fs::write(config_file.to_str().unwrap(), toml);
215                        data
216                    })
217                }
218            }
219            Err(_) => {
220                if pkg_name {
221                    let data = ConfigNew::new();
222                    fs::create_dir_all(config_file.parent().unwrap()).unwrap();
223                    let toml = toml::to_string(&data).unwrap();
224                    let _ = fs::write(config_file.to_str().unwrap(), toml);
225                    data.br_email
226                } else {
227                    let data = Config::new();
228                    fs::create_dir_all(config_file.parent().unwrap()).unwrap();
229                    let toml = toml::to_string(&data).unwrap();
230                    let _ = fs::write(config_file.to_str().unwrap(), toml);
231                    data
232                }
233            }
234        }
235    }
236    pub fn new() -> Self {
237        let mut connections = BTreeMap::new();
238        connections.insert("my_name".to_string(), Connection::default());
239        Self{
240            default: "my_name".to_string(),
241            connections,
242        }
243    }
244}
245#[derive(Clone, Debug, Deserialize, Serialize)]
246struct Connection {
247    /// 协议
248    protocol: Protocol,
249    /// 邮件地址
250    host: String,
251    /// 邮件端口
252    port: u16,
253    /// 邮件名称
254    name: String,
255    /// 邮件账号
256    mail: String,
257    /// 邮件密码
258    pass: String,
259    /// 邮件类型
260    email_type: EmailType,
261}
262impl Connection {
263    pub fn default() -> Connection {
264        Self {
265            protocol: Protocol::Smtp,
266            host: "smtp.exmail.qq.com".to_string(),
267            port: 25,
268            name: "发件人名".to_string(),
269            mail: "xxx@qq.com".to_string(),
270            pass: "*******".to_string(),
271            email_type: EmailType::Qq,
272        }
273    }
274}