use tokio::sync::mpsc; use super::{smtp::SmtpSender, EmailMessage}; /// Background email delivery via a tokio mpsc channel. pub struct EmailQueue { sender: mpsc::UnboundedSender, } struct QueuedEmail { msg: EmailMessage, } impl EmailQueue { /// Spawn a background worker that processes emails from the queue. /// The worker receives an SmtpSender. pub fn spawn(smtp: SmtpSender) -> Self { let (tx, mut rx) = mpsc::unbounded_channel::(); tokio::spawn(async move { while let Some(queued) = rx.recv().await { if let Err(e) = smtp.send(&queued.msg).await { tracing::error!("Failed to send queued email: {}", e); } } }); Self { sender: tx } } /// Enqueue an email for background delivery. pub fn enqueue(&self, msg: EmailMessage) -> Result<(), anyhow::Error> { self.sender.send(QueuedEmail { msg }).map_err(|_| anyhow::anyhow!("email queue is closed")) } /// Enqueue and return immediately. Errors are logged by the worker. pub fn enqueue_lossy(&self, msg: EmailMessage) { let _ = self.enqueue(msg); } }