一个简陋的 email 用户代理,遵循「计算机网络」课程项目 #2 的要求,用 Rust 实现。
项目地址(GitHub):https://github.com/Somnia1337/EchoUnityArchivist
展示
流程
登录:
写信:
收信:
登出 & 关闭:
细节
英语支持:
3 种行首标志:
>
:会话
✓
:成功
!
:出错
邮箱格式检查:
邮件分割线:
发送二次确认:
实现
使用的第三方 crate:
[dependencies]
imap = "2.4.1"
lettre = "0.11.6"
native-tls = "0.2.11"
得益于 Rust 强大的类型系统,实现此 CLI 应用的体验非常流畅、舒适,重构让代码更加优雅、可扩展,也让我对 Rust 有了更深的理解。
优雅地处理错误:
// Logout from IMAP server
println!("{}{}...", prompts.eua_logging_out, user.imap_domain);
match imap_cli.logout() {
Ok(_) => println!("{}", prompts.eua_logout_succeed),
Err(e) => println!("{}{:?}", prompts.eua_logout_fail, e),
}
轻松地持续读取并验证用户输入:
pub fn read_selection(prompt_read: &str, prompt_invalid: &str, lo: usize, hi: usize) -> usize {
loop {
match read_input(prompt_read).trim().parse().ok() {
Some(x) if x >= lo && x <= hi => return x,
_ => println!("{}{}.", prompt_invalid, hi),
}
}
}
lettre
库让发送逻辑变得简洁明了:
pub fn compose_and_send(
&self,
smtp_cli: &SmtpTransport,
prompts: &Prompts,
) -> Result<Option<String>, Box<dyn Error>> {
// ...
// Build the message
let email = Message::builder()
.from(self.email.clone().parse().unwrap())
.to(to.clone())
.subject(read_input(prompts.compose_subject))
.header(ContentType::TEXT_PLAIN)
.body(read_body(&prompts))
.unwrap();
// ...
// Reconfirm
if !read_reconfirmation(&prompts) {
return Ok(None);
}
// Send the message
println!("{}", prompts.send_sending);
match smtp_cli.send(&email) {
Ok(_) => Ok(Some(to.to_string())),
Err(e) => Err(Box::new(e)),
}
}
最后
500 余行的小项目(去掉“不那么优雅”的多语言实现就 300 余行),没有使用任何 Rust 高级特性(如 unsafe
黑魔法),就实现了一个相对健壮的 CLI 应用。
回看写了一年多的 Java,突然感觉不香了(一定是 skill issue🤣)。
BTW,昨天打完蓝桥杯了,今年 Java A 组题难度颇低,本周内写一写题解😉