spawn_access_control/notification/
email.rsuse crate::alert_system::{AlertNotification, NotificationError, EscalationLevel};
use crate::async_trait;
use lettre::{
transport::smtp::authentication::Credentials,
AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor,
};
use serde::{Serialize, Deserialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SmtpConfig {
pub host: String,
pub port: u16,
pub username: String,
pub password: String,
}
#[derive(Clone)]
pub struct EmailConfig {
pub smtp: SmtpConfig,
pub templates: EmailTemplates,
pub recipients: EmailRecipients,
}
#[derive(Clone)]
pub struct EmailTemplates {
pub alert_template: String,
}
#[derive(Clone)]
pub struct EmailRecipients {
pub primary: Vec<String>,
pub emergency: Vec<String>,
}
#[derive(Clone)]
pub struct EmailNotificationHandler {
config: EmailConfig,
transport: AsyncSmtpTransport<Tokio1Executor>,
}
impl EmailNotificationHandler {
pub fn new(config: EmailConfig) -> Result<Self, NotificationError> {
let creds = Credentials::new(
config.smtp.username.clone(),
config.smtp.password.clone(),
);
let transport = AsyncSmtpTransport::<Tokio1Executor>::relay(&config.smtp.host)
.map_err(|e| NotificationError::ConfigError(e.to_string()))?
.port(config.smtp.port)
.credentials(creds)
.build();
Ok(Self {
config,
transport,
})
}
fn render_alert_template(&self, notification: &AlertNotification) -> Result<String, NotificationError> {
Ok(format!("Alert: {}", notification.alert.message))
}
}
#[async_trait]
impl crate::alert_system::NotificationHandler for EmailNotificationHandler {
async fn send_notification(&self, notification: &AlertNotification) -> Result<(), NotificationError> {
let body = self.render_alert_template(notification)?;
let subject = format!(
"[{:?}] Alert: {} - {}",
notification.alert.severity,
notification.alert.metric_name,
notification.alert.message
);
let recipients = match notification.escalation_level {
EscalationLevel::Critical => {
self.config.recipients.emergency.clone()
}
_ => self.config.recipients.primary.clone(),
};
let email = Message::builder()
.subject(subject)
.body(body)
.map_err(|e| NotificationError::ConfigError(e.to_string()))?;
for _recipient in recipients {
self.transport
.send(email.clone())
.await
.map_err(|e| NotificationError::SendError(e.to_string()))?;
}
Ok(())
}
}