
Complete church management system with bulletin management, media processing, live streaming integration, and web interface. Includes authentication, email notifications, database migrations, and comprehensive test suite.
103 lines
3.7 KiB
Plaintext
103 lines
3.7 KiB
Plaintext
use lettre::{
|
|
transport::smtp::authentication::Credentials,
|
|
AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor,
|
|
};
|
|
use std::env;
|
|
|
|
use crate::{error::Result, models::PendingEvent};
|
|
|
|
#[derive(Clone)]
|
|
pub struct EmailConfig {
|
|
pub smtp_host: String,
|
|
pub smtp_port: u16,
|
|
pub smtp_user: String,
|
|
pub smtp_pass: String,
|
|
pub from_email: String,
|
|
pub admin_email: String,
|
|
}
|
|
|
|
impl EmailConfig {
|
|
pub fn from_env() -> Result<Self> {
|
|
Ok(EmailConfig {
|
|
smtp_host: env::var("SMTP_HOST").expect("SMTP_HOST not set"),
|
|
smtp_port: env::var("SMTP_PORT")
|
|
.unwrap_or_else(|_| "587".to_string())
|
|
.parse()
|
|
.expect("Invalid SMTP_PORT"),
|
|
smtp_user: env::var("SMTP_USER").expect("SMTP_USER not set"),
|
|
smtp_pass: env::var("SMTP_PASS").expect("SMTP_PASS not set"),
|
|
from_email: env::var("SMTP_FROM").expect("SMTP_FROM not set"),
|
|
admin_email: env::var("ADMIN_EMAIL").expect("ADMIN_EMAIL not set"),
|
|
})
|
|
}
|
|
}
|
|
|
|
pub struct Mailer {
|
|
transport: AsyncSmtpTransport<Tokio1Executor>,
|
|
config: EmailConfig,
|
|
}
|
|
|
|
impl Mailer {
|
|
pub fn new(config: EmailConfig) -> Result<Self> {
|
|
let creds = Credentials::new(config.smtp_user.clone(), config.smtp_pass.clone());
|
|
|
|
let transport = AsyncSmtpTransport::<Tokio1Executor>::starttls_relay(&config.smtp_host)?
|
|
.port(config.smtp_port)
|
|
.credentials(creds)
|
|
.build();
|
|
|
|
Ok(Mailer { transport, config })
|
|
}
|
|
|
|
pub async fn send_event_submission_notification(&self, event: &PendingEvent) -> Result<()> {
|
|
let email = Message::builder()
|
|
.from(self.config.from_email.parse()?)
|
|
.to(self.config.admin_email.parse()?)
|
|
.subject(&format!("New Event Submission: {}", event.title))
|
|
.body(format!(
|
|
"New event submitted for approval:\n\nTitle: {}\nDescription: {}\nStart: {}\nLocation: {}\nSubmitted by: {}",
|
|
event.title,
|
|
event.description,
|
|
event.start_time,
|
|
event.location,
|
|
event.submitter_email.as_deref().unwrap_or("Unknown")
|
|
))?;
|
|
|
|
self.transport.send(email).await?;
|
|
tracing::info!("Event submission email sent successfully");
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn send_event_approval_notification(&self, event: &PendingEvent, _admin_notes: Option<&str>) -> Result<()> {
|
|
if let Some(submitter_email) = &event.submitter_email {
|
|
let email = Message::builder()
|
|
.from(self.config.from_email.parse()?)
|
|
.to(submitter_email.parse()?)
|
|
.subject(&format!("Event Approved: {}", event.title))
|
|
.body(format!(
|
|
"Great news! Your event '{}' has been approved and will be published.",
|
|
event.title
|
|
))?;
|
|
|
|
self.transport.send(email).await?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn send_event_rejection_notification(&self, event: &PendingEvent, admin_notes: Option<&str>) -> Result<()> {
|
|
if let Some(submitter_email) = &event.submitter_email {
|
|
let email = Message::builder()
|
|
.from(self.config.from_email.parse()?)
|
|
.to(submitter_email.parse()?)
|
|
.subject(&format!("Event Update: {}", event.title))
|
|
.body(format!(
|
|
"Thank you for submitting '{}'. After review, we're unable to include this event at this time.\n\n{}",
|
|
event.title,
|
|
admin_notes.unwrap_or("Please feel free to submit future events.")
|
|
))?;
|
|
|
|
self.transport.send(email).await?;
|
|
}
|
|
Ok(())
|
|
|