Skip to main content

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;
96pub mod transport;
97
98mod matcher;
99mod processor;
100
101mod mailet;
102mod router;
103
104pub use bounce::generate_bounce;
105pub use mailet::{Mailet, MailetAction, MailetConfig, MailetError, MailetErrorPolicy};
106pub use matcher::Matcher;
107pub use processor::{ProcessingStep, Processor};
108pub use queue::{
109    FilesystemQueueStore, MailQueue, Priority, PriorityConfig, PriorityQueue, PriorityStats,
110    QueueEntry, QueueEntryData, QueueStats, QueueStore,
111};
112pub use rate_limit::{RateLimitConfig, RateLimitKey, RateLimiter};
113pub use router::MailProcessorRouter;
114pub use sieve::{
115    SieveAction, SieveCommand, SieveContext, SieveInterpreter, SieveScript, SieveTest,
116};
117pub use transport::{MailTransport, NullMailTransport, SmtpEnvelope};
118
119#[cfg(test)]
120pub mod test_helpers {
121    use bytes::Bytes;
122    use rusmes_proto::{HeaderMap, Mail, MailAddress, MessageBody, MimeMessage};
123    use std::str::FromStr;
124
125    /// Create a test mail with minimal setup
126    pub fn create_test_mail(sender: &str, recipients: Vec<&str>) -> Mail {
127        let sender_addr = MailAddress::from_str(sender).ok();
128        let recipient_addrs: Vec<MailAddress> = recipients
129            .iter()
130            .filter_map(|r| MailAddress::from_str(r).ok())
131            .collect();
132
133        let message = MimeMessage::new(
134            HeaderMap::new(),
135            MessageBody::Small(Bytes::from("Test message")),
136        );
137
138        Mail::new(sender_addr, recipient_addrs, message, None, None)
139    }
140}