rusmes_core/lib.rs
1//! # rusmes-core — Mailet Processing Engine for RusMES
2//!
3//! `rusmes-core` is the central mail-processing library for [RusMES], providing a composable
4//! pipeline of *matchers* and *mailets* that evaluate and transform incoming mail messages.
5//! It is modelled after the Apache James mailet API but implemented from scratch in async Rust.
6//!
7//! ## Architecture
8//!
9//! Mail processing flows through a [`Processor`] that applies a sequence of
10//! [`ProcessingStep`]s. Each step pairs a [`Matcher`] (decides *whether* to act) with a
11//! [`Mailet`] (decides *what* to do).
12//!
13//! ```text
14//! ┌─────────┐ ┌───────────────────────────────────────────────────┐
15//! │ Mail │────▶│ Processor │
16//! └─────────┘ │ Step 1: Matcher → Mailet (e.g. SpfCheck) │
17//! │ Step 2: Matcher → Mailet (e.g. DkimVerify) │
18//! │ Step 3: Matcher → Mailet (e.g. SieveMailet) │
19//! │ Step N: … │
20//! └───────────────────────────────────────────────────┘
21//! ```
22//!
23//! ## Included Mailets
24//!
25//! | Mailet | Purpose |
26//! |--------|---------|
27//! | [`mailets::AddHeaderMailet`] | Append arbitrary headers |
28//! | [`mailets::BounceMailet`] | RFC 3464 DSN bounce generation |
29//! | [`mailets::DkimVerifyMailet`] | DKIM signature verification (RFC 6376) |
30//! | [`mailets::DmarcVerifyMailet`] | DMARC policy enforcement (RFC 7489) |
31//! | [`mailets::DnsblMailet`] | DNS-based block-list lookups |
32//! | [`mailets::ForwardMailet`] | Forwarding with loop detection |
33//! | [`mailets::GreylistMailet`] | Greylisting anti-spam |
34//! | [`mailets::LegalisMailet`] | Legal archiving with RFC 3161 timestamps |
35//! | [`mailets::LocalDeliveryMailet`] | Local mailbox delivery |
36//! | `mailets::OxifyMailet` | AI-powered mail enrichment |
37//! | [`mailets::RemoteDeliveryMailet`] | SMTP relay delivery (Pure Rust / rustls) |
38//! | [`mailets::RemoveMimeHeaderMailet`] | Strip MIME headers by pattern |
39//! | [`mailets::SieveMailet`] | RFC 5228 Sieve script filtering |
40//! | [`mailets::SpamAssassinMailet`] | SpamAssassin integration |
41//! | [`mailets::SpfCheckMailet`] | SPF policy checking (RFC 7208) |
42//! | [`mailets::VirusScanMailet`] | ClamAV / virus-scan integration |
43//!
44//! ## Included Matchers
45//!
46//! | Matcher | Purpose |
47//! |---------|---------|
48//! | `CompositeAll` / `CompositeAny` | Boolean composition of other matchers |
49//! | `HasAttachment` | True when mail has MIME attachments |
50//! | `HeaderContains` | True when a header contains a substring |
51//! | `IsInBlacklist` | Sender/recipient on a configurable deny-list |
52//! | `IsInWhitelist` | Sender/recipient on a configurable allow-list |
53//! | `RecipientIsLocal` | True when recipient is a local domain |
54//! | `RemoteAddress` | True when client IP matches a CIDR range |
55//! | `SenderIs` | Exact or wildcard sender address match |
56//! | `SizeGreaterThan` | True when message exceeds a byte threshold |
57//!
58//! ## Protocol Support
59//!
60//! - **SMTP** – mail reception and relay (`rusmes-smtp`)
61//! - **IMAP4** – mail access (`rusmes-imap`)
62//! - **JMAP** – JSON Meta Application Protocol (`rusmes-jmap`)
63//! - **POP3** – legacy mail retrieval (`rusmes-pop3`)
64//!
65//! ## Feature Flags
66//!
67//! This crate currently has no optional feature flags; all components are always compiled.
68//!
69//! ## Quick-start Example
70//!
71//! ```rust,no_run
72//! use rusmes_core::{Processor, ProcessingStep};
73//! use rusmes_proto::MailState;
74//! use std::sync::Arc;
75//!
76//! # async fn build_processor() {
77//! // Build a basic processor that evaluates mail in the Root state
78//! let mut processor = Processor::new("transport", MailState::Root);
79//!
80//! // Steps are (matcher, mailet) pairs; add them via add_step(ProcessingStep::new(…))
81//! // See individual mailet and matcher types in the rusmes_core::mailets /
82//! // rusmes_core::matchers modules for concrete implementations.
83//! # }
84//! ```
85//!
86//! [RusMES]: https://github.com/cool-japan/rusmes
87
88pub mod bounce;
89pub mod dsn;
90pub mod factory;
91pub mod mailets;
92pub mod matchers;
93pub mod queue;
94pub mod rate_limit;
95pub mod sieve;
96
97mod matcher;
98mod processor;
99
100mod mailet;
101mod router;
102
103pub use bounce::generate_bounce;
104pub use mailet::{Mailet, MailetAction, MailetConfig};
105pub use matcher::Matcher;
106pub use processor::{ProcessingStep, Processor};
107pub use queue::{
108 FilesystemQueueStore, MailQueue, Priority, PriorityConfig, PriorityQueue, PriorityStats,
109 QueueEntry, QueueEntryData, QueueStats, QueueStore,
110};
111pub use rate_limit::{RateLimitConfig, RateLimiter};
112pub use router::MailProcessorRouter;
113pub use sieve::{
114 SieveAction, SieveCommand, SieveContext, SieveInterpreter, SieveScript, SieveTest,
115};
116
117#[cfg(test)]
118pub mod test_helpers {
119 use bytes::Bytes;
120 use rusmes_proto::{HeaderMap, Mail, MailAddress, MessageBody, MimeMessage};
121 use std::str::FromStr;
122
123 /// Create a test mail with minimal setup
124 pub fn create_test_mail(sender: &str, recipients: Vec<&str>) -> Mail {
125 let sender_addr = MailAddress::from_str(sender).ok();
126 let recipient_addrs: Vec<MailAddress> = recipients
127 .iter()
128 .filter_map(|r| MailAddress::from_str(r).ok())
129 .collect();
130
131 let message = MimeMessage::new(
132 HeaderMap::new(),
133 MessageBody::Small(Bytes::from("Test message")),
134 );
135
136 Mail::new(sender_addr, recipient_addrs, message, None, None)
137 }
138}