df_email/
smtp.rs

1use std::fs;
2use json::JsonValue;
3use lettre::{Message, SmtpTransport, Transport};
4use lettre::message::{Attachment, header, MultiPart, SinglePart};
5use lettre::message::header::ContentType;
6use lettre::transport::smtp::authentication::Credentials;
7use log::info;
8
9#[derive(Clone)]
10pub struct Smtp {
11    default: String,
12    connections: JsonValue,
13
14    send_name: String,
15    send_mail: String,
16    send_pass: String,
17
18    smtp_host: String,
19    smtp_port: u16,
20
21    to_name: String,
22    to_mail: String,
23    reply_to_name: String,
24    reply_to_mail: String,
25}
26
27impl Smtp {
28    /// 初始化
29    ///
30    /// * config 配置文件
31    /// ````json
32    /// {
33    ///   "pop3_host": "pop.test.com",
34    ///   "pop3_port": 995,
35    ///   "smtp_host": "smtp.test.com",
36    ///   "smtp_port": 465,
37    ///   "send_email": "tests@email.com",
38    ///   "send_pass": ""
39    /// }
40    /// ````
41    pub fn connect(config: JsonValue) -> Self {
42        if config.is_empty() {
43            return Self {
44                default: "".to_string(),
45                connections: JsonValue::Null,
46                send_name: "".to_string(),
47                send_mail: "".to_string(),
48                send_pass: "".to_string(),
49                smtp_host: "".to_string(),
50                smtp_port: 0,
51                to_name: "".to_string(),
52                to_mail: "".to_string(),
53                reply_to_name: "".to_string(),
54                reply_to_mail: "".to_string(),
55            };
56        }
57        let default = config["default"].to_string();
58        let connections = config["connections"].clone();
59        let connection = connections[default.clone()].clone();
60
61        let smtp_host = connection["smtp_host"].to_string();
62        let smtp_port = connection["smtp_port"].as_u16().unwrap();
63
64        let send_name = connection["send_name"].to_string();
65        let send_mail = connection["send_mail"].to_string();
66        let send_pass = connection["send_pass"].to_string();
67
68        Self {
69            default,
70            connections,
71            send_name,
72            send_mail,
73            send_pass,
74            smtp_host,
75            smtp_port,
76            to_name: String::new(),
77            to_mail: String::new(),
78            reply_to_name: String::new(),
79            reply_to_mail: String::new(),
80        }
81    }
82
83    pub fn change_connection(&mut self, name: &str) {
84        let connection = self.connections[name.clone()].clone();
85        self.default = name.to_string();
86        self.smtp_host = connection["smtp_host"].to_string();
87        self.smtp_port = connection["smtp_port"].as_u16().unwrap();
88        self.send_name = connection["send_name"].to_string();
89        self.send_mail = connection["send_mail"].to_string();
90        self.send_pass = connection["send_pass"].to_string();
91    }
92
93    /// 设置发件人名称
94    pub fn set_send_name(&mut self, send_name: &str) -> &mut Self {
95        self.send_name = send_name.to_string();
96        self
97    }
98
99    /// 收件人
100    /// * name 收件人名称
101    /// * mail 收件箱
102    pub fn to(&mut self, name: &str, mail: &str) -> &mut Self {
103        self.to_name = name.to_string();
104        self.to_mail = mail.to_string();
105        self
106    }
107    /// 抄送人
108    /// * name 收件人名称
109    /// * mail 收件箱
110    pub fn reply_to(&mut self, name: &str, mail: &str) -> &mut Self {
111        self.reply_to_name = name.to_string();
112        self.reply_to_mail = mail.to_string();
113        self
114    }
115
116    /// 附件
117    pub fn add_file(&mut self, path: &str, name: &str, content_type: &str) -> SinglePart {
118        let content_type = {
119            match content_type {
120                "pdf" => {
121                    ContentType::parse("application/pdf").unwrap()
122                }
123                "html" => {
124                    ContentType::parse("text/html").unwrap()
125                }
126                "jpeg" => {
127                    ContentType::parse("image/jpeg").unwrap()
128                }
129                "json" => {
130                    ContentType::parse("application/json").unwrap()
131                }
132                _ => {
133                    ContentType::parse("text/plain").unwrap()
134                }
135            }
136        };
137        return Attachment::new(name.to_string()).body(fs::read(path.clone()).unwrap(), content_type);
138    }
139    /// 发送
140    ///
141    /// * subject 主题
142    /// * body 内容
143    pub fn send(&mut self, subject: &str, body: &str, files: Vec<SinglePart>) -> bool {
144        let mut builder = Message::builder().from(format!("{} <{}>",self.send_name,self.send_mail).parse().unwrap()).subject(subject);
145
146        builder = builder.to(format!("{} <{}>", self.to_name, self.to_mail).parse().unwrap());
147
148        if !self.reply_to_name.is_empty() {
149            builder = builder.reply_to(format!("{} <{}>", self.reply_to_name, self.reply_to_mail).parse().unwrap());
150        }
151
152        let mut body = MultiPart::alternative().multipart(
153            MultiPart::alternative_plain_html(String::from("text/plain"), String::from(body))
154        ).singlepart(SinglePart::builder().header(header::ContentType::TEXT_PLAIN).body(String::from(body)));
155
156        if !files.is_empty() {
157            for file in files.iter() {
158                body = body.singlepart(file.clone()).clone();
159            }
160        }
161
162        let email = builder.multipart(body.clone()).unwrap();
163
164        let mailer = SmtpTransport::relay(self.smtp_host.as_str())
165            .unwrap()
166            .port(self.smtp_port)
167            .credentials(Credentials::new(self.send_mail.to_string(), self.send_pass.to_string()))
168            .build();
169        match mailer.send(&email) {
170            Ok(_) => {
171                true
172            }
173            Err(e) => {
174                info!("错误: {}", e);
175                false
176            }
177        }
178    }
179}