church-api/src/email.rs.backup
Benjamin Slingo 0c06e159bb Initial commit: Church API Rust implementation
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.
2025-08-19 20:56:41 -04:00

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(())