mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-22 11:00:19 +00:00
set up multi account
This commit is contained in:
parent
60af11bd47
commit
ff724cb5be
6 changed files with 117 additions and 55 deletions
|
@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Merge `Email` with `Msg` [#21]
|
- Merge `Email` with `Msg` [#21]
|
||||||
- List command with pagination [#19]
|
- List command with pagination [#19]
|
||||||
- Icon in table when attachment is present [#16]
|
- Icon in table when attachment is present [#16]
|
||||||
|
- Multi-account [#17]
|
||||||
|
|
||||||
[unreleased]: https://github.com/soywod/himalaya
|
[unreleased]: https://github.com/soywod/himalaya
|
||||||
|
|
||||||
|
@ -41,5 +42,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
[#14]: https://github.com/soywod/himalaya/issues/14
|
[#14]: https://github.com/soywod/himalaya/issues/14
|
||||||
[#15]: https://github.com/soywod/himalaya/issues/15
|
[#15]: https://github.com/soywod/himalaya/issues/15
|
||||||
[#16]: https://github.com/soywod/himalaya/issues/16
|
[#16]: https://github.com/soywod/himalaya/issues/16
|
||||||
|
[#17]: https://github.com/soywod/himalaya/issues/17
|
||||||
[#19]: https://github.com/soywod/himalaya/issues/19
|
[#19]: https://github.com/soywod/himalaya/issues/19
|
||||||
[#21]: https://github.com/soywod/himalaya/issues/21
|
[#21]: https://github.com/soywod/himalaya/issues/21
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use lettre::transport::smtp::authentication::Credentials;
|
use lettre::transport::smtp::authentication::Credentials as SmtpCredentials;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
env, fmt,
|
env, fmt,
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{self, Read},
|
io::{self, Read},
|
||||||
|
@ -15,8 +16,11 @@ use toml;
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
IoError(io::Error),
|
IoError(io::Error),
|
||||||
ParseTomlError(toml::de::Error),
|
ParseTomlError(toml::de::Error),
|
||||||
|
ParseTomlAccountsError,
|
||||||
GetEnvVarError(env::VarError),
|
GetEnvVarError(env::VarError),
|
||||||
GetPathNotFoundError,
|
GetPathNotFoundError,
|
||||||
|
GetAccountNotFoundError(String),
|
||||||
|
GetAccountDefaultNotFoundError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
@ -25,8 +29,11 @@ impl fmt::Display for Error {
|
||||||
match self {
|
match self {
|
||||||
Error::IoError(err) => err.fmt(f),
|
Error::IoError(err) => err.fmt(f),
|
||||||
Error::ParseTomlError(err) => err.fmt(f),
|
Error::ParseTomlError(err) => err.fmt(f),
|
||||||
|
Error::ParseTomlAccountsError => write!(f, "no account found"),
|
||||||
Error::GetEnvVarError(err) => err.fmt(f),
|
Error::GetEnvVarError(err) => err.fmt(f),
|
||||||
Error::GetPathNotFoundError => write!(f, "path not found"),
|
Error::GetPathNotFoundError => write!(f, "path not found"),
|
||||||
|
Error::GetAccountNotFoundError(account) => write!(f, "account {} not found", account),
|
||||||
|
Error::GetAccountDefaultNotFoundError => write!(f, "no default account found"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,33 +60,48 @@ impl From<env::VarError> for Error {
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
// Config
|
// Account
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct ServerInfo {
|
pub struct Account {
|
||||||
pub host: String,
|
// Override
|
||||||
pub port: u16,
|
pub name: Option<String>,
|
||||||
pub login: String,
|
pub downloads_dir: Option<PathBuf>,
|
||||||
pub password: String,
|
|
||||||
|
// Specific
|
||||||
|
pub default: Option<bool>,
|
||||||
|
pub email: String,
|
||||||
|
|
||||||
|
pub imap_host: String,
|
||||||
|
pub imap_port: u16,
|
||||||
|
pub imap_login: String,
|
||||||
|
pub imap_password: String,
|
||||||
|
|
||||||
|
pub smtp_host: String,
|
||||||
|
pub smtp_port: u16,
|
||||||
|
pub smtp_login: String,
|
||||||
|
pub smtp_password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerInfo {
|
impl Account {
|
||||||
pub fn get_addr(&self) -> (&str, u16) {
|
pub fn imap_addr(&self) -> (&str, u16) {
|
||||||
(&self.host, self.port)
|
(&self.imap_host, self.imap_port)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_smtp_creds(&self) -> Credentials {
|
pub fn smtp_creds(&self) -> SmtpCredentials {
|
||||||
Credentials::new(self.login.to_owned(), self.password.to_owned())
|
SmtpCredentials::new(self.smtp_login.to_owned(), self.smtp_password.to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Config
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub email: String,
|
|
||||||
pub downloads_dir: Option<PathBuf>,
|
pub downloads_dir: Option<PathBuf>,
|
||||||
pub imap: ServerInfo,
|
|
||||||
pub smtp: ServerInfo,
|
#[serde(flatten)]
|
||||||
|
pub accounts: HashMap<String, Account>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -124,14 +146,35 @@ impl Config {
|
||||||
Ok(toml::from_slice(&content)?)
|
Ok(toml::from_slice(&content)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn email_full(&self) -> String {
|
pub fn get_account(&self, name: Option<&str>) -> Result<&Account> {
|
||||||
format!("{} <{}>", self.name, self.email)
|
match name {
|
||||||
|
Some(name) => self
|
||||||
|
.accounts
|
||||||
|
.get(name)
|
||||||
|
.ok_or_else(|| Error::GetAccountNotFoundError(name.to_owned())),
|
||||||
|
None => self
|
||||||
|
.accounts
|
||||||
|
.iter()
|
||||||
|
.find(|(_, account)| account.default.unwrap_or(false))
|
||||||
|
.map(|(_, account)| account)
|
||||||
|
.ok_or_else(|| Error::GetAccountDefaultNotFoundError),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn downloads_filepath(&self, filename: &str) -> PathBuf {
|
pub fn downloads_filepath(&self, account: &Account, filename: &str) -> PathBuf {
|
||||||
let temp_dir = env::temp_dir();
|
let temp_dir = env::temp_dir();
|
||||||
let mut full_path = self.downloads_dir.as_ref().unwrap_or(&temp_dir).to_owned();
|
let mut full_path = account
|
||||||
|
.downloads_dir
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(self.downloads_dir.as_ref().unwrap_or(&temp_dir))
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
full_path.push(filename);
|
full_path.push(filename);
|
||||||
full_path
|
full_path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn address(&self, account: &Account) -> String {
|
||||||
|
let name = account.name.as_ref().unwrap_or(&self.name);
|
||||||
|
format!("{} <{}>", name, account.email)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/imap.rs
12
src/imap.rs
|
@ -2,7 +2,7 @@ use imap;
|
||||||
use native_tls::{self, TlsConnector, TlsStream};
|
use native_tls::{self, TlsConnector, TlsStream};
|
||||||
use std::{fmt, net::TcpStream, result};
|
use std::{fmt, net::TcpStream, result};
|
||||||
|
|
||||||
use crate::config;
|
use crate::config::Account;
|
||||||
use crate::mbox::Mbox;
|
use crate::mbox::Mbox;
|
||||||
use crate::msg::Msg;
|
use crate::msg::Msg;
|
||||||
|
|
||||||
|
@ -64,19 +64,19 @@ type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ImapConnector<'a> {
|
pub struct ImapConnector<'a> {
|
||||||
pub config: &'a config::ServerInfo,
|
pub account: &'a Account,
|
||||||
pub sess: imap::Session<TlsStream<TcpStream>>,
|
pub sess: imap::Session<TlsStream<TcpStream>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ImapConnector<'a> {
|
impl<'a> ImapConnector<'a> {
|
||||||
pub fn new(config: &'a config::ServerInfo) -> Result<Self> {
|
pub fn new(account: &'a Account) -> Result<Self> {
|
||||||
let tls = TlsConnector::new()?;
|
let tls = TlsConnector::new()?;
|
||||||
let client = imap::connect(config.get_addr(), &config.host, &tls)?;
|
let client = imap::connect(account.imap_addr(), &account.imap_host, &tls)?;
|
||||||
let sess = client
|
let sess = client
|
||||||
.login(&config.login, &config.password)
|
.login(&account.imap_login, &account.imap_password)
|
||||||
.map_err(|res| res.0)?;
|
.map_err(|res| res.0)?;
|
||||||
|
|
||||||
Ok(Self { config, sess })
|
Ok(Self { account, sess })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&mut self) {
|
pub fn close(&mut self) {
|
||||||
|
|
49
src/main.rs
49
src/main.rs
|
@ -117,6 +117,13 @@ fn run() -> Result<()> {
|
||||||
.about("📫 Minimalist CLI email client")
|
.about("📫 Minimalist CLI email client")
|
||||||
.author("soywod <clement.douin@posteo.net>")
|
.author("soywod <clement.douin@posteo.net>")
|
||||||
.setting(AppSettings::ArgRequiredElseHelp)
|
.setting(AppSettings::ArgRequiredElseHelp)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("account")
|
||||||
|
.long("account")
|
||||||
|
.short("a")
|
||||||
|
.help("Name of the config file to use")
|
||||||
|
.value_name("STRING"),
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("mailboxes")
|
SubCommand::with_name("mailboxes")
|
||||||
.aliases(&["mboxes", "mb", "m"])
|
.aliases(&["mboxes", "mb", "m"])
|
||||||
|
@ -191,9 +198,12 @@ fn run() -> Result<()> {
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
|
let account_name = matches.value_of("account");
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("mailboxes") {
|
if let Some(_) = matches.subcommand_matches("mailboxes") {
|
||||||
let config = Config::new_from_file()?;
|
let config = Config::new_from_file()?;
|
||||||
let mut imap_conn = ImapConnector::new(&config.imap)?;
|
let account = config.get_account(account_name)?;
|
||||||
|
let mut imap_conn = ImapConnector::new(&account)?;
|
||||||
|
|
||||||
let mboxes = imap_conn.list_mboxes()?;
|
let mboxes = imap_conn.list_mboxes()?;
|
||||||
println!("{}", mboxes.to_table());
|
println!("{}", mboxes.to_table());
|
||||||
|
@ -203,7 +213,8 @@ fn run() -> Result<()> {
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("list") {
|
if let Some(matches) = matches.subcommand_matches("list") {
|
||||||
let config = Config::new_from_file()?;
|
let config = Config::new_from_file()?;
|
||||||
let mut imap_conn = ImapConnector::new(&config.imap)?;
|
let account = config.get_account(account_name)?;
|
||||||
|
let mut imap_conn = ImapConnector::new(&account)?;
|
||||||
|
|
||||||
let mbox = matches.value_of("mailbox").unwrap();
|
let mbox = matches.value_of("mailbox").unwrap();
|
||||||
let page_size: u32 = matches
|
let page_size: u32 = matches
|
||||||
|
@ -225,7 +236,8 @@ fn run() -> Result<()> {
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("search") {
|
if let Some(matches) = matches.subcommand_matches("search") {
|
||||||
let config = Config::new_from_file()?;
|
let config = Config::new_from_file()?;
|
||||||
let mut imap_conn = ImapConnector::new(&config.imap)?;
|
let account = config.get_account(account_name)?;
|
||||||
|
let mut imap_conn = ImapConnector::new(&account)?;
|
||||||
|
|
||||||
let mbox = matches.value_of("mailbox").unwrap();
|
let mbox = matches.value_of("mailbox").unwrap();
|
||||||
let page_size: usize = matches
|
let page_size: usize = matches
|
||||||
|
@ -271,7 +283,8 @@ fn run() -> Result<()> {
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("read") {
|
if let Some(matches) = matches.subcommand_matches("read") {
|
||||||
let config = Config::new_from_file()?;
|
let config = Config::new_from_file()?;
|
||||||
let mut imap_conn = ImapConnector::new(&config.imap)?;
|
let account = config.get_account(account_name)?;
|
||||||
|
let mut imap_conn = ImapConnector::new(&account)?;
|
||||||
|
|
||||||
let mbox = matches.value_of("mailbox").unwrap();
|
let mbox = matches.value_of("mailbox").unwrap();
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -286,7 +299,8 @@ fn run() -> Result<()> {
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("attachments") {
|
if let Some(matches) = matches.subcommand_matches("attachments") {
|
||||||
let config = Config::new_from_file()?;
|
let config = Config::new_from_file()?;
|
||||||
let mut imap_conn = ImapConnector::new(&config.imap)?;
|
let account = config.get_account(account_name)?;
|
||||||
|
let mut imap_conn = ImapConnector::new(&account)?;
|
||||||
|
|
||||||
let mbox = matches.value_of("mailbox").unwrap();
|
let mbox = matches.value_of("mailbox").unwrap();
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -299,7 +313,7 @@ fn run() -> Result<()> {
|
||||||
} else {
|
} else {
|
||||||
println!("{} attachment(s) found for message {}", parts.len(), uid);
|
println!("{} attachment(s) found for message {}", parts.len(), uid);
|
||||||
parts.iter().for_each(|(filename, bytes)| {
|
parts.iter().for_each(|(filename, bytes)| {
|
||||||
let filepath = config.downloads_filepath(&filename);
|
let filepath = config.downloads_filepath(&account, &filename);
|
||||||
println!("Downloading {} …", filename);
|
println!("Downloading {} …", filename);
|
||||||
fs::write(filepath, bytes).unwrap()
|
fs::write(filepath, bytes).unwrap()
|
||||||
});
|
});
|
||||||
|
@ -311,16 +325,17 @@ fn run() -> Result<()> {
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("write") {
|
if let Some(_) = matches.subcommand_matches("write") {
|
||||||
let config = Config::new_from_file()?;
|
let config = Config::new_from_file()?;
|
||||||
let mut imap_conn = ImapConnector::new(&config.imap)?;
|
let account = config.get_account(account_name)?;
|
||||||
|
let mut imap_conn = ImapConnector::new(&account)?;
|
||||||
|
|
||||||
let tpl = Msg::build_new_tpl(&config)?;
|
let tpl = Msg::build_new_tpl(&config, &account)?;
|
||||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||||
let msg = Msg::from(content);
|
let msg = Msg::from(content);
|
||||||
|
|
||||||
input::ask_for_confirmation("Send the message?")?;
|
input::ask_for_confirmation("Send the message?")?;
|
||||||
|
|
||||||
println!("Sending …");
|
println!("Sending …");
|
||||||
smtp::send(&config.smtp, &msg.to_sendable_msg()?)?;
|
smtp::send(&account, &msg.to_sendable_msg()?)?;
|
||||||
imap_conn.append_msg("Sent", &msg.to_vec()?)?;
|
imap_conn.append_msg("Sent", &msg.to_vec()?)?;
|
||||||
println!("Done!");
|
println!("Done!");
|
||||||
|
|
||||||
|
@ -329,16 +344,17 @@ fn run() -> Result<()> {
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
if let Some(matches) = matches.subcommand_matches("reply") {
|
||||||
let config = Config::new_from_file()?;
|
let config = Config::new_from_file()?;
|
||||||
let mut imap_conn = ImapConnector::new(&config.imap)?;
|
let account = config.get_account(account_name)?;
|
||||||
|
let mut imap_conn = ImapConnector::new(&account)?;
|
||||||
|
|
||||||
let mbox = matches.value_of("mailbox").unwrap();
|
let mbox = matches.value_of("mailbox").unwrap();
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
|
||||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||||
let tpl = if matches.is_present("reply-all") {
|
let tpl = if matches.is_present("reply-all") {
|
||||||
msg.build_reply_all_tpl(&config)?
|
msg.build_reply_all_tpl(&config, &account)?
|
||||||
} else {
|
} else {
|
||||||
msg.build_reply_tpl(&config)?
|
msg.build_reply_tpl(&config, &account)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||||
|
@ -347,7 +363,7 @@ fn run() -> Result<()> {
|
||||||
input::ask_for_confirmation("Send the message?")?;
|
input::ask_for_confirmation("Send the message?")?;
|
||||||
|
|
||||||
println!("Sending …");
|
println!("Sending …");
|
||||||
smtp::send(&config.smtp, &msg.to_sendable_msg()?)?;
|
smtp::send(&account, &msg.to_sendable_msg()?)?;
|
||||||
imap_conn.append_msg("Sent", &msg.to_vec()?)?;
|
imap_conn.append_msg("Sent", &msg.to_vec()?)?;
|
||||||
println!("Done!");
|
println!("Done!");
|
||||||
|
|
||||||
|
@ -356,20 +372,21 @@ fn run() -> Result<()> {
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("forward") {
|
if let Some(matches) = matches.subcommand_matches("forward") {
|
||||||
let config = Config::new_from_file()?;
|
let config = Config::new_from_file()?;
|
||||||
let mut imap_conn = ImapConnector::new(&config.imap)?;
|
let account = config.get_account(account_name)?;
|
||||||
|
let mut imap_conn = ImapConnector::new(&account)?;
|
||||||
|
|
||||||
let mbox = matches.value_of("mailbox").unwrap();
|
let mbox = matches.value_of("mailbox").unwrap();
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
|
||||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||||
let tpl = msg.build_forward_tpl(&config)?;
|
let tpl = msg.build_forward_tpl(&config, &account)?;
|
||||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||||
let msg = Msg::from(content);
|
let msg = Msg::from(content);
|
||||||
|
|
||||||
input::ask_for_confirmation("Send the message?")?;
|
input::ask_for_confirmation("Send the message?")?;
|
||||||
|
|
||||||
println!("Sending …");
|
println!("Sending …");
|
||||||
smtp::send(&config.smtp, &msg.to_sendable_msg()?)?;
|
smtp::send(&account, &msg.to_sendable_msg()?)?;
|
||||||
imap_conn.append_msg("Sent", &msg.to_vec()?)?;
|
imap_conn.append_msg("Sent", &msg.to_vec()?)?;
|
||||||
println!("Done!");
|
println!("Done!");
|
||||||
|
|
||||||
|
|
20
src/msg.rs
20
src/msg.rs
|
@ -2,8 +2,8 @@ use lettre;
|
||||||
use mailparse::{self, MailHeaderMap};
|
use mailparse::{self, MailHeaderMap};
|
||||||
use std::{fmt, result};
|
use std::{fmt, result};
|
||||||
|
|
||||||
|
use crate::config::{Account, Config};
|
||||||
use crate::table::{self, DisplayRow, DisplayTable};
|
use crate::table::{self, DisplayRow, DisplayTable};
|
||||||
use crate::Config;
|
|
||||||
|
|
||||||
// Error wrapper
|
// Error wrapper
|
||||||
|
|
||||||
|
@ -208,11 +208,11 @@ impl<'a> Msg {
|
||||||
Ok(parts)
|
Ok(parts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_new_tpl(config: &Config) -> Result<String> {
|
pub fn build_new_tpl(config: &Config, account: &Account) -> Result<String> {
|
||||||
let mut tpl = vec![];
|
let mut tpl = vec![];
|
||||||
|
|
||||||
// "From" header
|
// "From" header
|
||||||
tpl.push(format!("From: {}", config.email_full()));
|
tpl.push(format!("From: {}", config.address(account)));
|
||||||
|
|
||||||
// "To" header
|
// "To" header
|
||||||
tpl.push("To: ".to_string());
|
tpl.push("To: ".to_string());
|
||||||
|
@ -223,13 +223,13 @@ impl<'a> Msg {
|
||||||
Ok(tpl.join("\r\n"))
|
Ok(tpl.join("\r\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_reply_tpl(&self, config: &Config) -> Result<String> {
|
pub fn build_reply_tpl(&self, config: &Config, account: &Account) -> Result<String> {
|
||||||
let msg = &self.parse()?;
|
let msg = &self.parse()?;
|
||||||
let headers = msg.get_headers();
|
let headers = msg.get_headers();
|
||||||
let mut tpl = vec![];
|
let mut tpl = vec![];
|
||||||
|
|
||||||
// "From" header
|
// "From" header
|
||||||
tpl.push(format!("From: {}", config.email_full()));
|
tpl.push(format!("From: {}", config.address(account)));
|
||||||
|
|
||||||
// "In-Reply-To" header
|
// "In-Reply-To" header
|
||||||
if let Some(msg_id) = headers.get_first_value("message-id") {
|
if let Some(msg_id) = headers.get_first_value("message-id") {
|
||||||
|
@ -263,13 +263,13 @@ impl<'a> Msg {
|
||||||
Ok(tpl.join("\r\n"))
|
Ok(tpl.join("\r\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_reply_all_tpl(&self, config: &Config) -> Result<String> {
|
pub fn build_reply_all_tpl(&self, config: &Config, account: &Account) -> Result<String> {
|
||||||
let msg = &self.parse()?;
|
let msg = &self.parse()?;
|
||||||
let headers = msg.get_headers();
|
let headers = msg.get_headers();
|
||||||
let mut tpl = vec![];
|
let mut tpl = vec![];
|
||||||
|
|
||||||
// "From" header
|
// "From" header
|
||||||
tpl.push(format!("From: {}", config.email_full()));
|
tpl.push(format!("From: {}", config.address(account)));
|
||||||
|
|
||||||
// "In-Reply-To" header
|
// "In-Reply-To" header
|
||||||
if let Some(msg_id) = headers.get_first_value("message-id") {
|
if let Some(msg_id) = headers.get_first_value("message-id") {
|
||||||
|
@ -278,7 +278,7 @@ impl<'a> Msg {
|
||||||
|
|
||||||
// "To" header
|
// "To" header
|
||||||
// All addresses coming from original "To" …
|
// All addresses coming from original "To" …
|
||||||
let email: lettre::Address = config.email.parse().unwrap();
|
let email: lettre::Address = account.email.parse().unwrap();
|
||||||
let to = headers
|
let to = headers
|
||||||
.get_all_values("to")
|
.get_all_values("to")
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -345,13 +345,13 @@ impl<'a> Msg {
|
||||||
Ok(tpl.join("\r\n"))
|
Ok(tpl.join("\r\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_forward_tpl(&self, config: &Config) -> Result<String> {
|
pub fn build_forward_tpl(&self, config: &Config, account: &Account) -> Result<String> {
|
||||||
let msg = &self.parse()?;
|
let msg = &self.parse()?;
|
||||||
let headers = msg.get_headers();
|
let headers = msg.get_headers();
|
||||||
let mut tpl = vec![];
|
let mut tpl = vec![];
|
||||||
|
|
||||||
// "From" header
|
// "From" header
|
||||||
tpl.push(format!("From: {}", config.email_full()));
|
tpl.push(format!("From: {}", config.address(account)));
|
||||||
|
|
||||||
// "To" header
|
// "To" header
|
||||||
tpl.push("To: ".to_string());
|
tpl.push("To: ".to_string());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use lettre;
|
use lettre;
|
||||||
use std::{fmt, result};
|
use std::{fmt, result};
|
||||||
|
|
||||||
use crate::config;
|
use crate::config::Account;
|
||||||
|
|
||||||
// Error wrapper
|
// Error wrapper
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@ type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
|
|
||||||
pub fn send(config: &config::ServerInfo, msg: &lettre::Message) -> Result<()> {
|
pub fn send(account: &Account, msg: &lettre::Message) -> Result<()> {
|
||||||
use lettre::Transport;
|
use lettre::Transport;
|
||||||
|
|
||||||
lettre::transport::smtp::SmtpTransport::relay(&config.host)?
|
lettre::transport::smtp::SmtpTransport::relay(&account.smtp_host)?
|
||||||
.credentials(config.to_smtp_creds())
|
.credentials(account.smtp_creds())
|
||||||
.build()
|
.build()
|
||||||
.send(msg)
|
.send(msg)
|
||||||
.map(|_| Ok(()))?
|
.map(|_| Ok(()))?
|
||||||
|
|
Loading…
Reference in a new issue