// // Copyright (c) 2025-2026 rustmailer.com (https://rustmailer.com) // // This file is part of the Bichon Email Archiving Project // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . use std::net::SocketAddr; use tokio::net::TcpListener; use tokio_rustls::TlsAcceptor; use crate::modules::{ common::signal::SIGNAL_MANAGER, settings::cli::{SmtpEncryptionMode, SETTINGS}, smtp::{ server::{run_smtp_server, run_smtps_server}, tls::create_acceptor, }, }; pub mod server; pub mod stream; pub mod tls; #[cfg(test)] mod tests; #[derive(Clone, Default)] pub struct SmtpConfig { pub whitelist: Option>, pub tls_acceptor: Option, pub auth_required: bool, } pub struct SmtpServer { pub smtp_addr: SocketAddr, smtp_handle: tokio::task::JoinHandle<()>, } impl SmtpServer { pub async fn stop(self) { let _ = self.smtp_handle.await; } } pub async fn start_smtp_server() -> std::io::Result { let smtp_port = SETTINGS.bichon_smtp_port; let tls_acceptor: Option = match SETTINGS.bichon_smtp_encryption { SmtpEncryptionMode::None => None, SmtpEncryptionMode::Starttls | SmtpEncryptionMode::Tls => Some(create_acceptor().await?), }; let smtp_listener = TcpListener::bind(( SETTINGS.bichon_bind_ip.clone().unwrap_or("0.0.0.0".into()), smtp_port, )) .await .map_err(|e| { if e.kind() == std::io::ErrorKind::AddrInUse { std::io::Error::other(format!( "SMTP port {smtp_port} is already in use. Is another instance running?" )) } else { e } })?; let smtp_addr = smtp_listener.local_addr()?; let smtp_config = SmtpConfig { whitelist: None, tls_acceptor: match SETTINGS.bichon_smtp_encryption { SmtpEncryptionMode::None | SmtpEncryptionMode::Tls => None, SmtpEncryptionMode::Starttls => tls_acceptor.clone(), }, auth_required: SETTINGS.bichon_smtp_auth_required, }; let smtp_shutdown = SIGNAL_MANAGER.subscribe(); let smtp_handle = if matches!(SETTINGS.bichon_smtp_encryption, SmtpEncryptionMode::Tls) { let acceptor = tls_acceptor .clone() .expect("TLS acceptor required when tls=true"); tokio::spawn(async move { run_smtps_server(smtp_listener, smtp_config, acceptor, smtp_shutdown).await; }) } else { tokio::spawn(async move { run_smtp_server(smtp_listener, smtp_config, smtp_shutdown).await; }) }; Ok(SmtpServer { smtp_addr, smtp_handle, }) }