commit 517f0f6252a4398a77ad82c027ecdcc7ba8e3f29 from: Thomas Böhler date: Sun Feb 25 09:55:15 2024 UTC feat: add option for STARTTLS The "starttls" configuration option and the "--smtp-starttls" command line flag are introduced to allow sending email over STARTTLS. Closes: https://todo.sr.ht/~witcher/rss-email/29 Signed-off-by: Thomas Böhler commit - fcea8dc69f246e04c5304af228295d1be740de3b commit + 517f0f6252a4398a77ad82c027ecdcc7ba8e3f29 blob - 624cf395311b55505b2460b0a3d3c080c634a919 blob + f379c0d2d23a269b0180391ffc3d79a2c1e07e71 --- config.example.toml +++ config.example.toml @@ -6,4 +6,5 @@ from = "sender " user = "user" password = "password" server = "server" -port = 25 +port = 587 +starttls = true blob - 9fc065d8a3530c5181f8e488fed904f404637791 blob + 3ed064590abc78d9aabcaee82fd5db329e1daba4 --- docs/rss-email.1.scd +++ docs/rss-email.1.scd @@ -73,6 +73,9 @@ The following options override the fields from the con *--smtp-user* _user_ SMTP user +*--smtp-starttls* + Enable SMTP STARTTLS + If all of these options are given, no configuration file will be read, and thus no configuration file is necessary. Missing options will be read from the configuration file. blob - 6490c3c51b3a1b8cdb5585794e6ade30b0290be3 blob + b4fc365ed7eebce284f9586d601772cd8f853447 --- docs/rss-email.5.scd +++ docs/rss-email.5.scd @@ -43,11 +43,14 @@ sending emails. The following attributes exist: - *password*: String - *server*: String - *port*: Int +- *starttls*: Bool *user* and *password* define the username and password used to authenticate with SMTP. *server* and *port* define the server and port of the SMTP server that -should be used. +should be used. *starttls* defines whether the server uses STARTTLS or not. +The attribute *starttls* is optional and defaults to *false*. + Note that it is currently not possible to specify a password in any other way than with the *password* attribute, meaning it has to be saved in plain-text. @@ -69,7 +72,8 @@ from = "sender " user = "user" password = "password" server = "server" -port = 25 +port = 587 +starttls = true ``` # FILES blob - 104d5f46d08cb482905330ea1282eebb8cfdcee6 blob + a70fa5913c25dc3a66bded36ec4511ba2f890e0c --- src/cli.rs +++ src/cli.rs @@ -54,6 +54,9 @@ pub struct Cli { /// SMTP server port #[clap(long, value_name = "port", value_parser = clap::value_parser!(u16).range(1..))] pub smtp_port: Option, + /// Enable SMTP STARTTLS + #[clap(long, value_name = "starttls")] + pub smtp_starttls: Option, } impl Cli { blob - 40cbfa995122f513006038b8b4c7d727aa91fbd6 blob + 897732853817e93e172b5ba94464b93b1e005ce7 --- src/config.rs +++ src/config.rs @@ -37,6 +37,7 @@ pub struct SmtpConfig { pub(crate) password: String, pub(crate) server: String, pub(crate) port: u16, + pub(crate) starttls: Option, } impl Config { @@ -74,6 +75,7 @@ pub struct AppConfig { pub smtp_password: String, pub smtp_server: String, pub smtp_port: u16, + pub smtp_starttls: bool, } impl AppConfig { @@ -100,6 +102,7 @@ impl AppConfig { cli.smtp_password, cli.smtp_server, cli.smtp_port, + cli.smtp_starttls, ) { ( Some(mail_from), @@ -108,6 +111,7 @@ impl AppConfig { Some(smtp_password), Some(smtp_server), Some(smtp_port), + Some(smtp_starttls), ) => { trace!("All necessary config values have been given on the command line, no need to check for config file"); s.mail_from = mail_from; @@ -116,8 +120,17 @@ impl AppConfig { s.smtp_password = smtp_password; s.smtp_server = smtp_server; s.smtp_port = smtp_port; + s.smtp_starttls = smtp_starttls; } - (mail_from, mail_to, smtp_user, smtp_password, smtp_server, smtp_port) => { + ( + mail_from, + mail_to, + smtp_user, + smtp_password, + smtp_server, + smtp_port, + smtp_starttls, + ) => { let cfg = Config::new(cli.config_path)?; s.mail_from = mail_from.unwrap_or(cfg.mail.from); s.mail_to = mail_to.unwrap_or(cfg.mail.to); @@ -125,6 +138,7 @@ impl AppConfig { s.smtp_password = smtp_password.unwrap_or(cfg.smtp.password); s.smtp_server = smtp_server.unwrap_or(cfg.smtp.server); s.smtp_port = smtp_port.unwrap_or(cfg.smtp.port); + s.smtp_starttls = smtp_starttls.or(cfg.smtp.starttls).unwrap_or(false); } } blob - 329f8a461200a7009871a4dd49684af78cb25f74 blob + 4e71447e5583ff7d6ea7b8bc25a3ad30fbd60f11 --- src/mail.rs +++ src/mail.rs @@ -83,14 +83,19 @@ pub fn get_mailer( password: String, server: &str, port: u16, + starttls: bool, ) -> Result, Error> { let creds = Credentials::new(user, password); - let mailer = AsyncSmtpTransport::::relay(server) - .context(SMTPSnafu)? - .credentials(creds) - .port(port) - .build(); + let mailer = if starttls { + AsyncSmtpTransport::::starttls_relay(server) + } else { + AsyncSmtpTransport::::relay(server) + } + .context(SMTPSnafu)? + .credentials(creds) + .port(port) + .build(); Ok(mailer) } blob - 4d2cb027064564aeef0b4eb645e702809adb82c2 blob + 74e412950d4074b2b18a24b90b59db88a0a9d388 --- src/main.rs +++ src/main.rs @@ -98,6 +98,7 @@ async fn app_main() -> Result<(), Error> { config.smtp_password.clone(), &config.smtp_server, config.smtp_port, + config.smtp_starttls, ) .context(MailSnafu)?;