swadhinbiswas 📧 fix: mail module cleanup - remove dead code, simplify error handling · 7/25/2026
e4f7f83
41 lines · 1.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use tokio::sync::mpsc;

use super::{smtp::SmtpSender, EmailMessage};

/// Background email delivery via a tokio mpsc channel.
pub struct EmailQueue {
    sender: mpsc::UnboundedSender<QueuedEmail>,
}

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::<QueuedEmail>();

        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);
    }
}