Skip to main content

mailsis_utils/
transformer.rs

1//! In-pipeline email message transformations.
2//!
3//! Transformers run after the SMTP `DATA` phase and before routing,
4//! allowing headers to be injected, authentication results to be checked,
5//! or other modifications to be applied to an [`EmailMessage`] in place.
6//! Concrete implementations live in the [`transformers`](crate::transformers)
7//! module.
8
9use std::{future::Future, pin::Pin};
10
11use tracing::debug;
12
13use crate::EmailMessage;
14
15/// Boxed future type for transformer operations, enabling async transformers.
16pub type TransformFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
17
18/// Trait for message transformers that modify emails in the pipeline.
19///
20/// Transformers run after [`EmailMessage`] construction and before routing,
21/// allowing in-place modification of message fields and body.
22/// Transformers may perform async operations such as DNS lookups.
23pub trait MessageTransformer: Send + Sync {
24    /// Transforms an email message in place, possibly performing async operations.
25    fn transform<'a>(&'a self, message: &'a mut EmailMessage) -> TransformFuture<'a>;
26
27    /// Returns the name of this transformer.
28    fn name(&self) -> &str;
29
30    /// Applies a list of transformers to a message in order.
31    fn apply<'a>(
32        transformers: &'a [Box<dyn MessageTransformer>],
33        message: &'a mut EmailMessage,
34    ) -> TransformFuture<'a>
35    where
36        Self: Sized,
37    {
38        Box::pin(async move {
39            for transformer in transformers {
40                debug!(transformer = transformer.name(), "Applying transformer");
41                transformer.transform(message).await;
42            }
43            message.rebuild();
44        })
45    }
46}