aboutsummaryrefslogtreecommitdiff
path: root/src/mail.rs
blob: d6a22b1794ae910f05f550d5f6fd25b326b4c904 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use std::{str::FromStr, sync::Arc, time::Duration};

use anyhow::{anyhow, Result};
use lettre::{
    message::Mailbox, transport::smtp::authentication::Credentials, Message, SmtpTransport,
    Transport,
};
use log::info;
use serde::Deserialize;

use crate::Config;

#[derive(Debug, Deserialize)]
pub struct MailConfig {
    mail_from: String,
    mail_to: Vec<String>,
    smtp_auth: SmtpAuth,
    smtp_port: u16,
    smtp_timeout: Option<f64>,
    smtp_server: String,
    smtp_username: Option<String>,
    smtp_password: Option<String>,
}

#[derive(Clone, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
enum SmtpAuth {
    Plain,
    Tls,
    Starttls,
}

pub async fn send_mail(
    config: &Arc<Config>,
    service: usize,
    check: usize,
    error: String,
) -> Result<()> {
    let config = config.to_owned();
    tokio::task::spawn_blocking(move || {
        if let Some(mconfig) = &config.mail {
            info!("sending mail!");
            let mut transport = match mconfig.smtp_auth {
                SmtpAuth::Plain => SmtpTransport::builder_dangerous(&mconfig.smtp_server),
                SmtpAuth::Tls => SmtpTransport::relay(&mconfig.smtp_server)?,
                SmtpAuth::Starttls => SmtpTransport::starttls_relay(&mconfig.smtp_server)?,
            }
            .port(mconfig.smtp_port);

            if let Some(username) = mconfig.smtp_username.clone() {
                let password = mconfig
                    .smtp_password
                    .clone()
                    .ok_or(anyhow!("smtp password missing"))?;
                transport = transport.credentials(Credentials::new(username, password));
            }
            if let Some(timeout) = mconfig.smtp_timeout {
                transport = transport.timeout(Some(Duration::from_secs_f64(timeout)))
            }
            let transport = transport.build();

            let service = &config.services[service];
            for recipient in mconfig.mail_to.iter().chain(service.mail_to.iter()) {
                let message = Message::builder()
                    .from(Mailbox::from_str(&mconfig.mail_from)?)
                    .to(Mailbox::from_str(&recipient)?)
                    .subject(format!("{} failed.", service.title))
                    .body(format!(
                        "Check {:?} reported:\n{}",
                        service.checks[check].display(),
                        error
                    ))?;
                transport.send(&message)?;
            }
        }
        Ok::<_, anyhow::Error>(())
    })
    .await??;
    Ok(())
}