set up smtp #4 + write email feature #8

This commit is contained in:
Clément DOUIN
2021-01-03 23:18:23 +01:00
parent 0a48df0567
commit 125c4e2b0e
6 changed files with 426 additions and 6 deletions
+6
View File
@@ -39,6 +39,12 @@ pub struct Config {
pub smtp: ServerInfo,
}
impl Config {
pub fn email_full(&self) -> String {
format!("{} <{}>", self.name, self.email)
}
}
pub fn from_xdg() -> Option<PathBuf> {
match env::var("XDG_CONFIG_HOME") {
Err(_) => None,
+36 -4
View File
@@ -1,8 +1,15 @@
mod config;
mod imap;
mod smtp;
mod table;
use clap::{App, Arg, SubCommand};
use std::io::prelude::*;
use std::{env, fs, process};
fn nem_email_tpl() -> String {
["To: ", "Subject: ", ""].join("\r\n")
}
fn mailbox_arg() -> Arg<'static, 'static> {
Arg::with_name("mailbox")
@@ -77,6 +84,10 @@ fn main() {
)
.get_matches();
if let Some(_) = matches.subcommand_matches("list") {
imap::list_mailboxes(&mut imap_sess).unwrap();
}
if let Some(matches) = matches.subcommand_matches("search") {
let mbox = matches.value_of("mailbox").unwrap();
@@ -108,10 +119,6 @@ fn main() {
}
}
if let Some(_) = matches.subcommand_matches("list") {
imap::list_mailboxes(&mut imap_sess).unwrap();
}
if let Some(matches) = matches.subcommand_matches("read") {
let mbox = matches.value_of("mailbox").unwrap();
let mime = matches.value_of("mime-type").unwrap();
@@ -120,4 +127,29 @@ fn main() {
imap::read_email(&mut imap_sess, mbox, uid, mime).unwrap();
}
}
if let Some(_) = matches.subcommand_matches("write") {
let mut draft_path = env::temp_dir();
draft_path.push("himalaya-draft.mail");
fs::File::create(&draft_path)
.expect("Could not create draft file")
.write(nem_email_tpl().as_bytes())
.expect("Could not write into draft file");
process::Command::new(env!("EDITOR"))
.arg(&draft_path)
.status()
.expect("Could not start $EDITOR");
let mut draft = String::new();
fs::File::open(&draft_path)
.expect("Could not open draft file")
.read_to_string(&mut draft)
.expect("Could not read draft file");
fs::remove_file(&draft_path).expect("Could not remove draft file");
smtp::send(&config, &draft.as_bytes());
}
}
+52
View File
@@ -0,0 +1,52 @@
use lettre::{
message::{header, Message, SinglePart},
transport::smtp::{authentication::Credentials, SmtpTransport},
Transport,
};
use mailparse;
use crate::config;
pub fn send(config: &config::Config, bytes: &[u8]) {
let email_origin = mailparse::parse_mail(bytes).unwrap();
let email = email_origin
.headers
.iter()
.fold(Message::builder(), |msg, h| {
match h.get_key().to_lowercase().as_str() {
"to" => msg.to(h.get_value().parse().unwrap()),
"cc" => match h.get_value().parse() {
Err(_) => msg,
Ok(addr) => msg.cc(addr),
},
"bcc" => match h.get_value().parse() {
Err(_) => msg,
Ok(addr) => msg.bcc(addr),
},
"subject" => msg.subject(h.get_value()),
_ => msg,
}
})
.from(config.email_full().parse().unwrap())
.singlepart(
SinglePart::builder()
.header(header::ContentType(
"text/plain; charset=utf-8".parse().unwrap(),
))
.header(header::ContentTransferEncoding::Base64)
.body(email_origin.get_body_raw().unwrap()),
)
.unwrap();
let creds = Credentials::new(config.smtp.login.clone(), config.smtp.password.clone());
let mailer = SmtpTransport::relay(&config.smtp.host)
.unwrap()
.credentials(creds)
.build();
println!("Sending ...");
match mailer.send(&email) {
Ok(_) => println!("Email sent successfully!"),
Err(e) => panic!("Could not send email: {:?}", e),
}
}