mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-21 18:40:19 +00:00
fix wizard serialization issues
This commit is contained in:
parent
a15e2c0442
commit
1246be8a5b
8 changed files with 383 additions and 37 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -1463,8 +1463,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "email-lib"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3b77f4c2aee25fe234194b651bfadc3b5a3e3c817ca8ba1cd0044f1dd462723"
|
||||
dependencies = [
|
||||
"advisory-lock",
|
||||
"anyhow",
|
||||
|
@ -2960,8 +2958,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "mml-lib"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3767365c25258656f689a63f645fff963c94716caba0dc079bf19c2119ea1df7"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"chumsky",
|
||||
|
@ -3714,8 +3710,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "process-lib"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76cb01de71b99c9d36dacf51218b950e03f80a86ee5f910ff723a1693796bad3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
|
@ -4252,8 +4246,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "secret-lib"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "545285fca1cf00676621557d25814d589264d5635e8a767c603b3ff89364370e"
|
||||
dependencies = [
|
||||
"keyring-lib",
|
||||
"process-lib",
|
||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -35,8 +35,8 @@ default = [
|
|||
"attachment",
|
||||
"template",
|
||||
|
||||
# "pgp-commands", # enable PGP based on shell commands
|
||||
# "pgp-gpg", # enable
|
||||
# "pgp-commands",
|
||||
# "pgp-gpg",
|
||||
# "pgp-native",
|
||||
]
|
||||
|
||||
|
@ -116,7 +116,7 @@ clap_mangen = "0.2"
|
|||
console = "0.15.2"
|
||||
dialoguer = "0.10.2"
|
||||
dirs = "4.0"
|
||||
email-lib = { version = "=0.20.0", default-features = false }
|
||||
email-lib = { version = "=0.20.1", default-features = false }
|
||||
email_address = "0.2.4"
|
||||
env_logger = "0.8"
|
||||
erased-serde = "0.3"
|
||||
|
@ -125,11 +125,11 @@ keyring-lib = "=0.3.2"
|
|||
log = "0.4"
|
||||
mail-builder = "0.3"
|
||||
md5 = "0.7.0"
|
||||
mml-lib = { version = "=1.0.6", default-features = false }
|
||||
mml-lib = { version = "=1.0.7", default-features = false }
|
||||
oauth-lib = "=0.1.0"
|
||||
once_cell = "1.16"
|
||||
process-lib = "=0.3.0"
|
||||
secret-lib = "=0.3.2"
|
||||
process-lib = "=0.3.1"
|
||||
secret-lib = "=0.3.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
shellexpand-utils = "=0.2.0"
|
||||
|
|
|
@ -88,7 +88,7 @@ If you just want to **discuss** about the project, feel free to join the [Matrix
|
|||
Special thanks to the [NLnet foundation](https://nlnet.nl/project/Himalaya/index.html) and the [European Commission](https://www.ngi.eu/) that helped the project to receive financial support from:
|
||||
|
||||
- [NGI Assure](https://nlnet.nl/assure/) in 2022
|
||||
- [NGI Zero Untrust](https://nlnet.nl/entrust/) in 2023
|
||||
- [NGI Zero Entrust](https://nlnet.nl/entrust/) in 2023
|
||||
|
||||
If you appreciate the project, feel free to donate using one of the following providers:
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
# Rust
|
||||
rust-toolchain
|
||||
cargo-watch
|
||||
|
||||
# OpenSSL
|
||||
openssl.dev
|
||||
|
|
|
@ -45,10 +45,10 @@ pub struct TomlAccountConfig {
|
|||
pub flag: Option<FlagConfig>,
|
||||
pub message: Option<MessageConfig>,
|
||||
|
||||
#[cfg(feature = "maildir")]
|
||||
pub maildir: Option<MaildirConfig>,
|
||||
#[cfg(feature = "imap")]
|
||||
pub imap: Option<ImapConfig>,
|
||||
#[cfg(feature = "maildir")]
|
||||
pub maildir: Option<MaildirConfig>,
|
||||
#[cfg(feature = "notmuch")]
|
||||
pub notmuch: Option<NotmuchConfig>,
|
||||
#[cfg(feature = "smtp")]
|
||||
|
|
|
@ -94,16 +94,21 @@ pub(crate) async fn configure(path: PathBuf) -> Result<TomlConfig> {
|
|||
let path = expand::path(path);
|
||||
|
||||
println!("Writing the configuration to {path:?}…");
|
||||
let toml = pretty_serialize(&config)?;
|
||||
fs::create_dir_all(path.parent().unwrap_or(&path))?;
|
||||
fs::write(path, toml)?;
|
||||
|
||||
let mut doc = toml::to_string(&config)?.parse::<Document>()?;
|
||||
println!("Exiting the wizard…");
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
fn pretty_serialize(config: &TomlConfig) -> Result<String> {
|
||||
let mut doc: Document = toml::to_string(&config)?.parse()?;
|
||||
|
||||
doc.iter_mut().for_each(|(_, item)| {
|
||||
set_table_dotted(item, "folder-aliases");
|
||||
set_table_dotted(item, "sync-folders-strategy");
|
||||
|
||||
set_table_dotted(item, "folder");
|
||||
if let Some(item) = get_table_mut(item, "folder") {
|
||||
set_tables_dotted(item, ["add", "list", "expunge", "purge", "delete"]);
|
||||
set_tables_dotted(item, ["alias", "add", "list", "expunge", "purge", "delete"]);
|
||||
}
|
||||
|
||||
set_table_dotted(item, "envelope");
|
||||
|
@ -124,7 +129,9 @@ pub(crate) async fn configure(path: PathBuf) -> Result<TomlConfig> {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "maildir")]
|
||||
set_table_dotted(item, "maildir");
|
||||
|
||||
#[cfg(feature = "imap")]
|
||||
{
|
||||
set_table_dotted(item, "imap");
|
||||
|
@ -132,9 +139,10 @@ pub(crate) async fn configure(path: PathBuf) -> Result<TomlConfig> {
|
|||
set_tables_dotted(item, ["passwd", "oauth2"]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "notmuch")]
|
||||
set_table_dotted(item, "notmuch");
|
||||
set_table_dotted(item, "sendmail");
|
||||
|
||||
#[cfg(feature = "smtp")]
|
||||
{
|
||||
set_table_dotted(item, "smtp");
|
||||
|
@ -143,14 +151,22 @@ pub(crate) async fn configure(path: PathBuf) -> Result<TomlConfig> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sendmail")]
|
||||
set_table_dotted(item, "sendmail");
|
||||
|
||||
#[cfg(feature = "account-sync")]
|
||||
{
|
||||
set_table_dotted(item, "sync");
|
||||
if let Some(item) = get_table_mut(item, "sync") {
|
||||
set_tables_dotted(item, ["strategy"]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "pgp")]
|
||||
set_table_dotted(item, "pgp");
|
||||
});
|
||||
|
||||
fs::create_dir_all(path.parent().unwrap_or(&path))?;
|
||||
fs::write(path, doc.to_string())?;
|
||||
|
||||
Ok(config)
|
||||
Ok(doc.to_string())
|
||||
}
|
||||
|
||||
fn get_table_mut<'a>(item: &'a mut Item, key: &'a str) -> Option<&'a mut Item> {
|
||||
|
@ -168,3 +184,336 @@ fn set_tables_dotted<'a>(item: &'a mut Item, keys: impl IntoIterator<Item = &'a
|
|||
set_table_dotted(item, key)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{account::config::TomlAccountConfig, config::TomlConfig};
|
||||
|
||||
fn assert_eq(config: TomlAccountConfig, expected_toml: &str) {
|
||||
let config = TomlConfig {
|
||||
accounts: HashMap::from_iter([("test".into(), config)]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let toml = super::pretty_serialize(&config).expect("serialize error");
|
||||
assert_eq!(toml, expected_toml);
|
||||
|
||||
let expected_config = toml::from_str(&toml).expect("deserialize error");
|
||||
assert_eq!(config, expected_config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pretty_serialize_default() {
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "account-sync")]
|
||||
#[test]
|
||||
fn pretty_serialize_sync_all() {
|
||||
use email::{account::sync::config::SyncConfig, folder::sync::FolderSyncStrategy};
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
sync: Some(SyncConfig {
|
||||
enable: Some(false),
|
||||
dir: Some("/tmp/test".into()),
|
||||
strategy: Some(FolderSyncStrategy::All),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
sync.enable = false
|
||||
sync.dir = "/tmp/test"
|
||||
sync.strategy = "all"
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "account-sync")]
|
||||
#[test]
|
||||
fn pretty_serialize_sync_include() {
|
||||
use std::collections::HashSet;
|
||||
|
||||
use email::{account::sync::config::SyncConfig, folder::sync::FolderSyncStrategy};
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
sync: Some(SyncConfig {
|
||||
enable: Some(true),
|
||||
dir: Some("/tmp/test".into()),
|
||||
strategy: Some(FolderSyncStrategy::Include(HashSet::from_iter([
|
||||
"test".into()
|
||||
]))),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
sync.enable = true
|
||||
sync.dir = "/tmp/test"
|
||||
sync.strategy.include = ["test"]
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "imap")]
|
||||
#[test]
|
||||
fn pretty_serialize_imap_passwd_cmd() {
|
||||
use email::{
|
||||
account::config::passwd::PasswdConfig,
|
||||
imap::config::{ImapAuthConfig, ImapConfig},
|
||||
};
|
||||
use secret::Secret;
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
imap: Some(ImapConfig {
|
||||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: ImapAuthConfig::Passwd(PasswdConfig(Secret::new_cmd("pass show test"))),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
imap.host = "localhost"
|
||||
imap.port = 143
|
||||
imap.login = "test@localhost"
|
||||
imap.passwd.cmd = "pass show test"
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "imap")]
|
||||
#[test]
|
||||
fn pretty_serialize_imap_passwd_cmds() {
|
||||
use email::{
|
||||
account::config::passwd::PasswdConfig,
|
||||
imap::config::{ImapAuthConfig, ImapConfig},
|
||||
};
|
||||
use secret::Secret;
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
imap: Some(ImapConfig {
|
||||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: ImapAuthConfig::Passwd(PasswdConfig(Secret::new_cmd(vec![
|
||||
"pass show test",
|
||||
"tr -d '[:blank:]'",
|
||||
]))),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
imap.host = "localhost"
|
||||
imap.port = 143
|
||||
imap.login = "test@localhost"
|
||||
imap.passwd.cmd = ["pass show test", "tr -d '[:blank:]'"]
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "imap")]
|
||||
#[test]
|
||||
fn pretty_serialize_imap_oauth2() {
|
||||
use email::{
|
||||
account::config::oauth2::OAuth2Config,
|
||||
imap::config::{ImapAuthConfig, ImapConfig},
|
||||
};
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
imap: Some(ImapConfig {
|
||||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: ImapAuthConfig::OAuth2(OAuth2Config {
|
||||
client_id: "client-id".into(),
|
||||
auth_url: "auth-url".into(),
|
||||
token_url: "token-url".into(),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
imap.host = "localhost"
|
||||
imap.port = 143
|
||||
imap.login = "test@localhost"
|
||||
imap.oauth2.method = "xoauth2"
|
||||
imap.oauth2.client-id = "client-id"
|
||||
imap.oauth2.auth-url = "auth-url"
|
||||
imap.oauth2.token-url = "token-url"
|
||||
imap.oauth2.pkce = false
|
||||
imap.oauth2.scopes = []
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "maildir")]
|
||||
#[test]
|
||||
fn pretty_serialize_maildir() {
|
||||
use email::maildir::config::MaildirConfig;
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
maildir: Some(MaildirConfig {
|
||||
root_dir: "/tmp/test".into(),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
maildir.root-dir = "/tmp/test"
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "smtp")]
|
||||
#[test]
|
||||
fn pretty_serialize_smtp_passwd_cmd() {
|
||||
use email::{
|
||||
account::config::passwd::PasswdConfig,
|
||||
smtp::config::{SmtpAuthConfig, SmtpConfig},
|
||||
};
|
||||
use secret::Secret;
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
smtp: Some(SmtpConfig {
|
||||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: SmtpAuthConfig::Passwd(PasswdConfig(Secret::new_cmd("pass show test"))),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
smtp.host = "localhost"
|
||||
smtp.port = 143
|
||||
smtp.login = "test@localhost"
|
||||
smtp.passwd.cmd = "pass show test"
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "smtp")]
|
||||
#[test]
|
||||
fn pretty_serialize_smtp_passwd_cmds() {
|
||||
use email::{
|
||||
account::config::passwd::PasswdConfig,
|
||||
smtp::config::{SmtpAuthConfig, SmtpConfig},
|
||||
};
|
||||
use secret::Secret;
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
smtp: Some(SmtpConfig {
|
||||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: SmtpAuthConfig::Passwd(PasswdConfig(Secret::new_cmd(vec![
|
||||
"pass show test",
|
||||
"tr -d '[:blank:]'",
|
||||
]))),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
smtp.host = "localhost"
|
||||
smtp.port = 143
|
||||
smtp.login = "test@localhost"
|
||||
smtp.passwd.cmd = ["pass show test", "tr -d '[:blank:]'"]
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "smtp")]
|
||||
#[test]
|
||||
fn pretty_serialize_smtp_oauth2() {
|
||||
use email::{
|
||||
account::config::oauth2::OAuth2Config,
|
||||
smtp::config::{SmtpAuthConfig, SmtpConfig},
|
||||
};
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
smtp: Some(SmtpConfig {
|
||||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: SmtpAuthConfig::OAuth2(OAuth2Config {
|
||||
client_id: "client-id".into(),
|
||||
auth_url: "auth-url".into(),
|
||||
token_url: "token-url".into(),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
smtp.host = "localhost"
|
||||
smtp.port = 143
|
||||
smtp.login = "test@localhost"
|
||||
smtp.oauth2.method = "xoauth2"
|
||||
smtp.oauth2.client-id = "client-id"
|
||||
smtp.oauth2.auth-url = "auth-url"
|
||||
smtp.oauth2.token-url = "token-url"
|
||||
smtp.oauth2.pkce = false
|
||||
smtp.oauth2.scopes = []
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "pgp")]
|
||||
#[test]
|
||||
fn pretty_serialize_pgp_cmds() {
|
||||
use email::account::config::pgp::PgpConfig;
|
||||
|
||||
assert_eq(
|
||||
TomlAccountConfig {
|
||||
email: "test@localhost".into(),
|
||||
pgp: Some(PgpConfig::Cmds(Default::default())),
|
||||
..Default::default()
|
||||
},
|
||||
r#"[test]
|
||||
email = "test@localhost"
|
||||
pgp.backend = "cmds"
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,8 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
|
||||
let auth = if oauth2_enabled {
|
||||
let mut config = OAuth2Config::default();
|
||||
let redirect_host = OAuth2Config::LOCALHOST.to_owned();
|
||||
let redirect_port = OAuth2Config::get_first_available_port()?;
|
||||
|
||||
let method_idx = Select::with_theme(&*THEME)
|
||||
.with_prompt("IMAP OAuth 2.0 mechanism")
|
||||
|
@ -245,13 +247,13 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
config.auth_url.clone(),
|
||||
config.token_url.clone(),
|
||||
)?
|
||||
.with_redirect_host(config.redirect_host.clone())
|
||||
.with_redirect_port(config.redirect_port)
|
||||
.with_redirect_host(redirect_host.to_owned())
|
||||
.with_redirect_port(redirect_port)
|
||||
.build()?;
|
||||
|
||||
let mut auth_code_grant = AuthorizationCodeGrant::new()
|
||||
.with_redirect_host(config.redirect_host.clone())
|
||||
.with_redirect_port(config.redirect_port);
|
||||
.with_redirect_host(redirect_host.to_owned())
|
||||
.with_redirect_port(redirect_port);
|
||||
|
||||
if config.pkce {
|
||||
auth_code_grant = auth_code_grant.with_pkce();
|
||||
|
@ -312,7 +314,7 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
_ => Default::default(),
|
||||
};
|
||||
|
||||
ImapAuthConfig::Passwd(PasswdConfig { passwd: secret })
|
||||
ImapAuthConfig::Passwd(PasswdConfig(secret))
|
||||
};
|
||||
|
||||
let config = ImapConfig {
|
||||
|
|
|
@ -135,6 +135,8 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
|
||||
let auth = if oauth2_enabled {
|
||||
let mut config = OAuth2Config::default();
|
||||
let redirect_host = OAuth2Config::LOCALHOST;
|
||||
let redirect_port = OAuth2Config::get_first_available_port()?;
|
||||
|
||||
let method_idx = Select::with_theme(&*THEME)
|
||||
.with_prompt("SMTP OAuth 2.0 mechanism")
|
||||
|
@ -245,13 +247,13 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
config.auth_url.clone(),
|
||||
config.token_url.clone(),
|
||||
)?
|
||||
.with_redirect_host(config.redirect_host.clone())
|
||||
.with_redirect_port(config.redirect_port)
|
||||
.with_redirect_host(redirect_host.to_owned())
|
||||
.with_redirect_port(redirect_port)
|
||||
.build()?;
|
||||
|
||||
let mut auth_code_grant = AuthorizationCodeGrant::new()
|
||||
.with_redirect_host(config.redirect_host.clone())
|
||||
.with_redirect_port(config.redirect_port);
|
||||
.with_redirect_host(redirect_host.to_owned())
|
||||
.with_redirect_port(redirect_port);
|
||||
|
||||
if config.pkce {
|
||||
auth_code_grant = auth_code_grant.with_pkce();
|
||||
|
@ -312,7 +314,7 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
_ => Default::default(),
|
||||
};
|
||||
|
||||
SmtpAuthConfig::Passwd(PasswdConfig { passwd: secret })
|
||||
SmtpAuthConfig::Passwd(PasswdConfig(secret))
|
||||
};
|
||||
|
||||
let config = SmtpConfig {
|
||||
|
|
Loading…
Reference in a new issue