commit ccb62d531454eb4b79b334d3d72be07aa85f4101 from: witcher date: Mon Aug 15 12:11:57 2022 UTC Extract config and mailer modules Closes: https://todo.sr.ht/~witcher/rss-email/9 commit - 30dde916b02b22cd1840d13fb35276990bceeb53 commit + ccb62d531454eb4b79b334d3d72be07aa85f4101 blob - /dev/null blob + 85c1ee63806afb4fcefa06f257000848678997ee (mode 644) --- /dev/null +++ src/config.rs @@ -0,0 +1,34 @@ +use serde::Deserialize; +use std::fs::File; +use anyhow::Context; +use std::{io::Read, path::Path}; + +#[derive(Debug, Deserialize)] +pub struct Config { + pub(crate) to: String, + pub(crate) from: String, + pub(crate) smtp: SmtpConfig, +} + +#[derive(Debug, Deserialize)] +pub struct SmtpConfig { + pub(crate) user: String, + pub(crate) password: String, + pub(crate) server: String, + pub(crate) port: u16, +} + +impl Config { + pub fn new(config_path: impl AsRef) -> anyhow::Result { + let mut string = String::new(); + File::open(config_path.as_ref()) + .context(format!( + "File {:?} does not exist", + &config_path.as_ref() + ))? + .read_to_string(&mut string)?; + let config: Config = toml::de::from_str(&string)?; + + Ok(config) + } +} blob - c5901238843b8aa956544d407f87f932190b9b83 blob + 3e3c0785340d6941347d6763d076362cb20d4381 --- src/main.rs +++ src/main.rs @@ -8,49 +8,30 @@ extern crate anyhow; extern crate diesel_migrations; pub mod cli; +pub mod config; pub mod db; +pub mod mail; pub mod models; pub mod rss; pub mod schema; use self::diesel::prelude::*; use anyhow::Context; +use config::Config; use schema::posts::dsl::*; -use serde::Deserialize; -use std::fs::File; -use std::io::BufRead; -use std::io::BufReader; -use std::io::Read; +use std::{ + fs::File, + io::{BufRead, BufReader}, +}; +use crate::mail::{get_mailer, send_email}; -#[derive(Debug, Deserialize)] -struct Config<'a> { - to: &'a str, - from: &'a str, - smtp: SmtpConfig<'a>, -} - -#[derive(Debug, Deserialize)] -struct SmtpConfig<'a> { - user: &'a str, - password: &'a str, - server: &'a str, - port: u16, -} - fn main() -> anyhow::Result<()> { diesel_migrations::embed_migrations!("migrations/"); env_logger::init(); let args = cli::Cli::build_app()?; - let mut string = String::new(); - File::open(args.config_path.as_ref().unwrap()) - .context(format!( - "File {:?} does not exist", - &args.config_path.unwrap() - ))? - .read_to_string(&mut string)?; - let config: Config = toml::de::from_str(&string)?; + let config = Config::new(args.config_path.unwrap())?; dbg!(&config); let urls = BufReader::new( @@ -89,63 +70,18 @@ fn main() -> anyhow::Result<()> { } fn send_posts(config: &Config, items: Vec, dry_run: bool) -> anyhow::Result<()> { + let mailer = get_mailer(config)?; for mut post in items { if !dry_run { let subject = post.title.unwrap_or_else(|| "No title found".to_string()); // TODO: always append url instead // https://todo.sr.ht/~witcher/rss-email/7 let body = post.content.unwrap_or_else(|| post.url.unwrap()); - send_email(config, subject, body)?; + send_email(config, subject, body, &mailer)?; } post.sent = true; } + // TODO: mark posts as sent in database, too Ok(()) } - -fn send_email(config: &Config, subject: S, body: I) -> anyhow::Result<()> -where - S: AsRef, - I: Into, -{ - use lettre::{ - message::Message, - transport::{ - smtp::{ - authentication::Credentials, - client::{Tls, TlsParameters}, - SmtpTransport, - }, - Transport, - }, - }; - - let email = Message::builder() - .from(config.from.parse()?) - .to(config.to.parse()?) - .subject(subject.as_ref()) - .body(body.into())?; - - let creds = Credentials::new( - config.smtp.user.to_string(), - config.smtp.password.to_string(), - ); - - let tls = TlsParameters::builder(config.smtp.server.to_string()) - .dangerous_accept_invalid_certs(true) - .build()?; - - let mailer = SmtpTransport::relay(config.smtp.server)? - .tls(Tls::Opportunistic(tls)) - .credentials(creds) - .port(config.smtp.port) - .build(); - - // TODO: extract mailer to only be constructed once and reused - // https://todo.sr.ht/~witcher/rss-email/9 - // TODO: allow TLS, specify via config? - // https://todo.sr.ht/~witcher/rss-email/8 - mailer.send(&email)?; - - Ok(()) -} blob - /dev/null blob + 98c81d0675870c295c157e7fb817f9132755c138 (mode 644) --- /dev/null +++ src/mail.rs @@ -0,0 +1,52 @@ +use crate::config::Config; +use lettre::{ + message::Message, + transport::smtp::{ + authentication::Credentials, + client::{Tls, TlsParameters}, + SmtpTransport, + }, + Transport, +}; + +pub fn get_mailer(config: &Config) -> anyhow::Result { + let creds = Credentials::new( + config.smtp.user.to_string(), + config.smtp.password.to_string(), + ); + + // TODO: allow TLS, specify via config? + // https://todo.sr.ht/~witcher/rss-email/8 + let tls = TlsParameters::builder(config.smtp.server.to_string()) + .dangerous_accept_invalid_certs(true) + .build()?; + + let mailer = SmtpTransport::relay(&config.smtp.server)? + .tls(Tls::Opportunistic(tls)) + .credentials(creds) + .port(config.smtp.port) + .build(); + + Ok(mailer) +} + +pub fn send_email( + config: &Config, + subject: S, + body: I, + mailer: &SmtpTransport, +) -> anyhow::Result<()> +where + S: AsRef, + I: Into, +{ + let email = Message::builder() + .from(config.from.parse()?) + .to(config.to.parse()?) + .subject(subject.as_ref()) + .body(body.into())?; + + mailer.send(&email)?; + + Ok(()) +}