rusmes_smtp/lib.rs
1//! SMTP protocol implementation for RusMES
2//!
3//! This crate provides a full-featured, RFC 5321-compliant SMTP server
4//! implementation built on Tokio for asynchronous I/O.
5//!
6//! # Features
7//!
8//! - **RFC 5321 Compliance**: Complete SMTP protocol including HELO/EHLO,
9//! MAIL FROM, RCPT TO, DATA, QUIT, RSET, NOOP, and VRFY.
10//! - **STARTTLS** (RFC 3207): Opportunistic TLS upgrade for secure transport.
11//! - **AUTH** (RFC 4954): Multiple SASL mechanisms:
12//! - PLAIN (RFC 4616)
13//! - LOGIN
14//! - CRAM-MD5 (RFC 2195)
15//! - SCRAM-SHA-256 (RFC 5802 / RFC 7677)
16//! - **PIPELINING** (RFC 2920): Client-side pipelining support.
17//! - **DSN** (RFC 3461): Delivery Status Notification extensions.
18//! - **CHUNKING / BDAT** (RFC 3030): Binary data transfer without dot-stuffing.
19//! - **SIZE** (RFC 1870): Message size declaration.
20//! - **8BITMIME** (RFC 6152): 8-bit MIME content transfer.
21//! - **SMTPUTF8** (RFC 6531): Unicode email addresses.
22//! - **Submission** (RFC 4409 / RFC 6409): MSA mode on port 587.
23//!
24//! # Modules
25//!
26//! - [`auth`]: SASL authentication mechanism implementations.
27//! - [`bdat`]: BDAT/CHUNKING extension state machine (RFC 3030).
28//! - [`command`]: SMTP command types and parameters.
29//! - [`dsn`]: Delivery Status Notification parameter parsing (RFC 3461).
30//! - [`parser`]: Nom-based SMTP command parser.
31//! - [`response`]: SMTP response code formatting.
32//! - [`server`]: Async TCP listener and connection acceptor.
33//! - [`session`]: Per-connection state machine and command dispatcher.
34//! - [`submission`]: Mail Submission Agent (MSA) server variant.
35//!
36//! # Quick Start
37//!
38//! ```no_run
39//! use std::sync::Arc;
40//! use rusmes_smtp::{SmtpConfig, SmtpServer};
41//!
42//! #[tokio::main]
43//! async fn main() -> anyhow::Result<()> {
44//! let config = SmtpConfig {
45//! hostname: "mail.example.com".to_string(),
46//! max_message_size: 10 * 1024 * 1024, // 10 MiB
47//! require_auth: false,
48//! enable_starttls: false,
49//! ..Default::default()
50//! };
51//! // Build and run the server (requires auth/storage backends)
52//! // let server = SmtpServer::new(config, auth_backend, storage_backend);
53//! // server.listen("0.0.0.0:25").await?;
54//! Ok(())
55//! }
56//! ```
57
58pub mod auth;
59pub mod bdat;
60pub mod command;
61pub mod dsn;
62pub mod parser;
63pub mod response;
64pub mod server;
65pub mod session;
66pub mod submission;
67
68use ipnetwork::IpNetwork;
69use std::net::IpAddr;
70
71pub use bdat::{BdatCommand, BdatError, BdatState};
72pub use command::{MailParam, SmtpCommand};
73pub use dsn::{DsnError, DsnMailParams, DsnNotify, DsnRcptParams, DsnRet};
74pub use parser::parse_command;
75pub use response::SmtpResponse;
76pub use server::SmtpServer;
77pub use session::{SmtpConfig, SmtpSession, SmtpSessionHandler, SmtpState};
78pub use submission::{SubmissionConfig, SubmissionServer};
79
80/// Check if an IP address is in any of the given CIDR networks
81///
82/// # Arguments
83/// * `ip` - The IP address to check
84/// * `networks` - Vector of CIDR network strings (e.g., "192.168.0.0/16")
85///
86/// # Returns
87/// `true` if the IP is in any of the networks, `false` otherwise
88pub fn is_ip_in_networks(ip: IpAddr, networks: &[String]) -> bool {
89 for network_str in networks {
90 if let Ok(network) = network_str.parse::<IpNetwork>() {
91 if network.contains(ip) {
92 return true;
93 }
94 } else {
95 tracing::warn!("Invalid CIDR notation in relay_networks: {}", network_str);
96 }
97 }
98 false
99}