//! The log transport: each message becomes one file under `/mail-log/`. For development //! and tests (`[mail] transport = "log"`). The files hold the full body, one-time links included, //! so this transport is not for production. use std::path::PathBuf; use forge_core::mail::{MailError, OutgoingMail}; use super::{Mailer, SendFuture}; /// Writes messages to a directory. pub struct LogMailer { dir: PathBuf, } impl LogMailer { pub fn new(dir: PathBuf) -> LogMailer { LogMailer { dir } } async fn write(&self, mail: &OutgoingMail) -> Result<(), MailError> { tokio::fs::create_dir_all(&self.dir) .await .map_err(|e| MailError::Transient(format!("cannot create the mail log: {e}")))?; let name = format!("{}.txt", ulid::Ulid::generate()); let mut text = format!("To: {}\nSubject: {}\n", mail.to, mail.subject); if let Some(id) = &mail.message_id { text.push_str(&format!("Message-ID: {id}\n")); } if let Some(parent) = &mail.in_reply_to { text.push_str(&format!("In-Reply-To: {parent}\nReferences: {parent}\n")); } text.push_str(&format!("\n{}", mail.body)); tokio::fs::write(self.dir.join(name), text) .await .map_err(|e| MailError::Transient(format!("cannot write the mail log: {e}"))) } } impl Mailer for LogMailer { fn send<'a>(&'a self, mail: &'a OutgoingMail) -> SendFuture<'a> { Box::pin(self.write(mail)) } }