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}