gargoyle_email_notifier/
lib.rs

1use gargoyle::Notify;
2
3use lettre::{
4    Message, 
5    transport::smtp::authentication::Credentials, 
6    SmtpTransport, 
7    Transport
8};
9
10pub use lettre::{
11    message::Mailbox,
12    Address,
13};
14
15use log::info;
16
17/// Send an email notification.
18///
19/// # Example
20///
21/// ```
22/// # use std::thread::sleep;
23/// # use std::time::Duration;
24/// use gargoyle::{modules::{notify, monitor}, Schedule};
25/// let service_name = "nginx";
26/// let service_monitor = monitor::ExactService::new(service_name);
27/// let email_notifier = notify::Email {
28///     from: "The Gargoyle <from@example.com>".parse().unwrap(),
29///     to: "Administrator <admin@example.com>".parse().unwrap(),
30///     relay: "smtp.example.com".to_string(),
31///     smtp_username: "username".to_string(),
32///     smtp_password: "password".to_string(),
33/// };
34/// let mut schedule = Schedule::default();
35/// schedule.add(
36///     &format!("The Gargoyle has detected that {service_name} has gone down"),
37///     &format!("The Gargoyle has detected that {service_name} has recovered"),
38///     Duration::from_secs(60),
39///     &service_monitor,
40///     &email_notifier,
41/// );
42///     
43/// loop {
44///     schedule.run();
45///     sleep(Duration::from_millis(100));
46/// }
47/// ```
48pub struct Email {
49    pub from: Mailbox,
50    pub to: Mailbox,
51    pub relay: String,
52    pub smtp_username: String,
53    pub smtp_password: String,
54}
55
56/// Sends an email notification.
57impl Notify for Email {
58    fn send(&self, msg: &str, diagnostic: Option<String>) -> Result<(), String> {
59        let email = Message::builder()
60            .from(self.from.clone())
61            .to(self.to.clone())
62            .subject(msg)
63            .body(diagnostic.unwrap_or(msg.to_string()))
64            .map_err(|e| format!("Failed to build a message: {e}"))?;
65
66        let creds = Credentials::new(self.smtp_username.clone(), self.smtp_password.clone());
67
68        let mailer = SmtpTransport::relay(&self.relay)
69            .map_err(|e| format!("Failed to create a mailer: {e}"))?
70            .credentials(creds)
71            .build();
72
73        info!("Sending email notification from {} to {} via {}.", self.from, self.to, self.relay);
74        match mailer.send(&email) {
75            Ok(_) => Ok(()),
76            Err(e) => Err(format!("Failed to send email: {e}")),
77        }
78    }
79}
80