elektromail 0.1.0

A minimal, Rust-based IMAP + SMTP mail server for local development and testing
Documentation
//! Elektromail server binary entrypoint.

use std::net::{IpAddr, Ipv4Addr, SocketAddr};

use elektromail::{AuthConfig, Server, ServerConfig, StorageBackend};

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let smtp_port: u16 = std::env::var("SMTP_PORT")
        .ok()
        .and_then(|p| p.parse().ok())
        .unwrap_or(2525);

    let imap_port: u16 = std::env::var("IMAP_PORT")
        .ok()
        .and_then(|p| p.parse().ok())
        .unwrap_or(1143);

    let bind_addr: IpAddr = std::env::var("BIND_ADDR")
        .ok()
        .and_then(|a| a.parse().ok())
        .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED));

    let http_port: Option<u16> = std::env::var("HTTP_PORT").ok().and_then(|p| p.parse().ok());

    let storage = std::env::var("ELEKTROMAIL_DB")
        .ok()
        .map(StorageBackend::Sqlite)
        .unwrap_or(StorageBackend::InMemory);

    let auth = AuthConfig::from_env();
    let config = ServerConfig {
        smtp_addr: SocketAddr::new(bind_addr, smtp_port),
        imap_addr: SocketAddr::new(bind_addr, imap_port),
        http_addr: http_port.map(|p| SocketAddr::new(bind_addr, p)),
        auth: Some(auth.clone()),
        storage,
    };

    eprintln!("elektromail starting...");
    eprintln!("  SMTP: {}", config.smtp_addr);
    eprintln!("  IMAP: {}", config.imap_addr);
    if let Some(addr) = &config.http_addr {
        eprintln!("  HTTP: {}", addr);
    }
    if auth.user_count() == 0 {
        eprintln!("  Credentials: user / pass");
    } else {
        eprintln!(
            "  Credentials: ELEKTROMAIL_USERS ({} user(s))",
            auth.user_count()
        );
    }

    let server = Server::start(config).await?;

    eprintln!("Server running. Press Ctrl+C to stop.");

    tokio::signal::ctrl_c().await?;

    eprintln!("Shutting down...");
    server.stop().await?;

    Ok(())
}