Commit Diff


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<Path>) -> anyhow::Result<Config> {
+        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<models::Post>, 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<S, I>(config: &Config, subject: S, body: I) -> anyhow::Result<()>
-where
-    S: AsRef<str>,
-    I: Into<String>,
-{
-    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<SmtpTransport> {
+    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<S, I>(
+    config: &Config,
+    subject: S,
+    body: I,
+    mailer: &SmtpTransport,
+) -> anyhow::Result<()>
+where
+    S: AsRef<str>,
+    I: Into<String>,
+{
+    let email = Message::builder()
+        .from(config.from.parse()?)
+        .to(config.to.parse()?)
+        .subject(subject.as_ref())
+        .body(body.into())?;
+
+    mailer.send(&email)?;
+
+    Ok(())
+}