# smtp_recv : Secure, High-Performance SMTP Server

A complete, secure-by-default SMTP server implementation in Rust, designed for high performance and modern security standards.

## Table of Contents

- [Features](#features)
- [Usage](#usage)
- [Design](#design)
- [Tech Stack](#tech-stack)
- [Directory Structure](#directory-structure)
- [API Reference](#api-reference)
- [History](#history)

## Features

- **Implicit TLS (SMTPS)**: Enforces encryption from the start of the connection.
- **SNI Support**: Automatically selects the correct certificate based on the domain name.
- **Dynamic Certificate Loading**: Integrates with `cert_by_host` for efficient SSL certificate management in SaaS environments. Certificates are loaded asynchronously on-demand, significantly reducing memory usage when handling hundreds or thousands of domains.
- **Automatic Certificate Expiration**: Leverages `cert_by_host` to refresh certificates without service restarts. The cache automatically expires certificates based on their validity period, ensuring only valid certificates are served.
- **SMTP Authentication**: Supports `AUTH PLAIN` and `AUTH LOGIN`.
- **Pipeline Support**: Implements RFC 2920 SMTP command pipelining for efficiency.
- **Async I/O**: Built on `tokio` for high-performance asynchronous processing.
- **Extensible**: Custom email handling via the `Mailer` trait.

## Usage

Implement the `Mailer` trait to define how to handle received emails.

```rust
use smtp_recv::{run, Mailer, Result};
use mail_struct::UserMail;

struct MyMailer;

impl Mailer for MyMailer {
    async fn send(&self, user_mail: UserMail) -> anyhow::Result<()> {
        println!("Received mail from: {}", user_mail.mail.sender);
        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Run SMTP server on port 465
    // Requires implementation of Auth and CertByHost traits
    run(465, my_auth, MyMailer, my_ssl).await
}
```

## Design

The server follows a secure connection flow:

1.  **Connection**: Accepts TCP connection.
2.  **TLS Handshake**: Initiates Implicit TLS immediately.
3.  **SNI Extraction**: Extracts the server name from the ClientHello.
4.  **Certificate Selection**: Fetches the appropriate certificate using `CertByHost` with `cert_by_host` integration. This enables:
    - **Asynchronous Loading**: Certificates are loaded on-demand from Kvrocks, avoiding upfront loading of all certificates for SaaS platforms with hundreds or thousands of domains.
    - **Intelligent Caching**: `cert_by_host` provides a high-performance in-memory cache with automatic expiration based on certificate validity periods.
    - **Resource Efficiency**: Only active certificates are kept in memory, significantly reducing resource consumption compared to traditional approaches.
5.  **Session**: Establishes an SMTP session (`Session::run`).
6.  **Command Processing**: Handles SMTP commands (HELO, MAIL, RCPT, DATA) with pipelining support.
7.  **Authentication**: Verifies credentials using the `Auth` trait.
8.  **Delivery**: Delivers the email via the `Mailer` trait.

## Tech Stack

-   **Runtime**: `tokio`
-   **TLS**: `rustls`, `tokio-rustls`
-   **Certificate Management**: `cert_by_host` for dynamic SSL certificate loading
-   **Error Handling**: `anyhow`, `thiserror`
-   **Logging**: `log`

## Directory Structure

```
src/
├── lib.rs       # Library entry point, server run loop
├── error.rs     # Error definitions
├── mailer.rs    # Mailer trait definition
└── session.rs   # SMTP session handling logic
```

## API Reference

### `run`

```rust
pub async fn run<A: Auth, M: Mailer>(
    port: u16,
    auth: A,
    mailer: impl Into<Arc<M>>,
    ssl: impl CertByHost,
) -> Result<()>
```

Starts the SMTP server.
-   `port`: Listening port (usually 465).
-   `auth`: Authentication provider.
-   `mailer`: Email handler.
-   `ssl`: Certificate provider.

### `Mailer` Trait

```rust
pub trait Mailer: Send + Sync + 'static {
    fn send(&self, mail: UserMail) -> impl Future<Output = Result<()>> + Send;
}
```

Implement this to handle received emails.

### `UserMail` Struct

Contains the email data (`Mail`) and the user ID associated with the recipient.

## CertByHost Trait and Integration

`smtp_recv` uses the `ssl_trait::CertByHost` trait for dynamic SSL certificate loading. This design allows you to implement custom certificate providers or use the built-in `cert_by_host` integration.

### The `CertByHost` Trait

```rust
pub trait CertByHost: Send + Sync + 'static {
    type Item: Borrow<SslConfig>;
    async fn get(&self, host: &str) -> anyhow::Result<Option<Self::Item>>;
}
```

The trait provides an asynchronous method to fetch SSL certificates based on the hostname. This enables:
- **On-demand loading**: Certificates are loaded only when needed
- **Asynchronous operations**: Non-blocking certificate retrieval
- **Flexible backends**: Support for various storage systems (Kvrocks, databases, etc.)

### Using `cert_by_host` Integration

The `cert_by_host` crate provides a ready-to-use implementation that offers:
- **High-performance caching**: In-memory cache with concurrent reads
- **Automatic expiration**: Certificates that are about to expire will automatically re-access the redis/kvrocks database and reload
- **Resource efficiency**: Only active certificates are kept in memory

Here's how to use `cert_by_host` with `smtp_recv`:

```rust
use smtp_recv::{run, Mailer, Result};
use mail_struct::UserMail;
use cert_by_host::CertByHost as CertByHostImpl;

struct MyMailer;

impl Mailer for MyMailer {
    async fn send(&self, user_mail: UserMail) -> anyhow::Result<()> {
        println!("Received mail from: {}", user_mail.mail.sender);
        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize cert_by_host system
    xboot::init().await?;

    // Create cert_by_host provider
    let ssl_provider = CertByHostImpl;

    // Run SMTP server with cert_by_host integration
    run(465, my_auth, MyMailer, ssl_provider).await
}
```

### Custom Certificate Provider Example

You can also implement your own certificate provider:

```rust
use ssl_trait::{CertByHost, SslConfig};
use rustls::pki_types::{PrivateKeyDer, CertificateDer};
use std::borrow::Borrow;

struct MyCertProvider;

impl CertByHost for MyCertProvider {
    type Item = SslConfig;
    
    async fn get(&self, host: &str) -> anyhow::Result<Option<Self::Item>> {
        // Your custom logic to load certificates
        // e.g., from database, filesystem, or external API
        if host == "example.com" {
            let key = PrivateKeyDer::Pkcs8(/* load key */);
            let cert = vec![CertificateDer::from(/* load cert */)];
            Ok(Some(SslConfig { key, cert }))
        } else {
            Ok(None)
        }
    }
}
```

### Benefits for SaaS Applications

When running a SaaS platform with hundreds or thousands of domains:
1. **Memory efficiency**: Only certificates for active domains are loaded
2. **Automatic refresh**: Certificates that are about to expire will automatically re-access the redis/kvrocks database and reload
3. **No service restart**: New certificates can be added without restarting the server
4. **Scalability**: Handles large numbers of domains with minimal resource usage

## History

**The Story of Port 465**

In 1997, port 465 was registered for "SMTPS" - SMTP over SSL. It was intended to be the secure equivalent of port 25, encrypting the connection from the very beginning (Implicit TLS). However, it was never officially standardized by the IETF.

In 1998, the IETF standardized STARTTLS on port 587, which starts as plain text and upgrades to TLS. Port 465 was reassigned and considered deprecated for SMTP.

Despite this, many major email providers (like Gmail) continued to support port 465 because it is often more robust against misconfigured firewalls or intermediaries that might strip the STARTTLS command. Today, port 465 with Implicit TLS has seen a resurgence and is widely recommended for secure email submission, offering a "secure or nothing" approach that prevents downgrade attacks.