Explore Code
This page gives a quick overview of the LSMTPD repository structure so contributors can navigate the codebase easily.
LSMTP follows a modular architecture where each module has a single responsibility. Networking, SMTP handling, queueing, configuration, models, and error handling are isolated into separate components, making the project easier to understand, extend, and maintain.
Repository Layout
LSMTP/
├── Cargo.toml
├── Cargo.lock
├── README.md
├── LICENSE
├── CITATION.cff
├── LSMTP-Paper.pdf
│
├── src/
│ ├── main.rs
│ ├── state.rs
│ ├── errors.rs
│ │
│ ├── handler/
│ │ ├── mod.rs
│ │ └── email.rs
│ │
│ ├── models/
│ │ ├── mod.rs
│ │ ├── configs.rs
│ │ └── email.rs
│ │
│ └── queue/
│ ├── mod.rs
│ └── amqp.rs
│
├── packages/
└── target/
Source Directory
src/
The src directory contains all application source code.
It is divided into independent modules, each responsible for a specific subsystem.
src/main.rs
src/main.rs
Purpose
Application entry point.
This file starts the SMTP server and initializes every subsystem required for operation.
Typical responsibilities include:
- Loading configuration
- Initializing global state
- Creating communication channels
- Starting background workers
- Binding the TCP listener
- Accepting client connections
- Spawning asynchronous SMTP sessions
No SMTP protocol logic should be implemented here.
Instead, main.rs delegates work to dedicated modules.
src/state.rs
src/state.rs
Purpose
Application state management and initialization.
This module is responsible for resources shared across the application.
Examples include:
- Global configuration
- Shared channels
- Runtime state
- Startup helpers
- Initialization routines
This keeps global application logic separate from protocol handling.
src/errors.rs
src/errors.rs
Purpose
Centralized error definitions.
Instead of creating unrelated error types throughout the project, LSMTP defines common application errors in one location.
Benefits include:
- Consistent error handling
- Easier debugging
- Cleaner propagation with
? - Simpler logging
Every subsystem should use these common error types whenever possible.
handler/
src/
└── handler/
├── mod.rs
└── email.rs
Purpose
Implements the SMTP protocol.
This module communicates directly with connected SMTP clients.
Its responsibilities include:
- Reading SMTP commands
- Parsing protocol messages
- Validating SMTP state
- Sending server responses
- Receiving message bodies
- Building email objects
This is the core networking component of LSMTP.
handler/mod.rs
Module declaration.
Exports the public interfaces of the handler module.
handler/email.rs
Contains the SMTP session implementation.
Typical responsibilities include:
- Connection lifecycle
- SMTP command processing
- DATA mode handling
- Command validation
- Session state management
- Email construction
Every connected client is typically represented by an independent handler instance.
models/
src/
└── models/
├── mod.rs
├── configs.rs
└── email.rs
Purpose
Contains pure data structures.
Models should contain data only.
They should avoid networking logic, filesystem operations, or queue interactions whenever possible.
models/mod.rs
Exports every model defined inside the module.
Acts as the public interface for all shared structures.
models/configs.rs
Defines configuration structures used throughout LSMTP.
Typical examples include:
- Server configuration
- AMQP configuration
- Queue configuration
- Runtime options
- Environment variable mappings
Keeping configuration isolated makes initialization predictable and maintainable.
models/email.rs
Defines the internal representation of an email.
This structure is passed throughout the application after SMTP reception.
Typical information includes:
- Sender
- Recipients
- Subject
- Headers
- Body
- Metadata
- Timestamp
- Queue information
This model acts as the canonical representation of an email inside LSMTP.
queue/
src/
└── queue/
├── mod.rs
└── amqp.rs
Purpose
Responsible for asynchronous message delivery.
Instead of processing emails directly inside SMTP sessions, messages are forwarded to the queue subsystem.
This keeps SMTP connections responsive and minimizes client wait times.
queue/mod.rs
Exports queue-related functionality.
Acts as the public interface of the queue module.
queue/amqp.rs
Implements the AMQP publisher.
Responsibilities typically include:
- Establishing AMQP connections
- Creating channels
- Publishing messages
- Confirming delivery
- Handling reconnections
- Reporting queue failures
This module isolates all RabbitMQ-specific logic from the rest of the application.
target/
target/
Rust build output directory.
Contains:
- Compiled binaries
- Incremental compilation cache
- Dependency artifacts
- Release builds
- Debug builds
This directory is automatically generated by Cargo and should not be modified manually.
Module Dependency Overview
The overall dependency hierarchy is intentionally simple.
main.rs
│
├── state
├── handler
├── queue
├── models
└── errors
The handler module depends on shared models and error definitions.
The queue subsystem consumes email models produced by the handler.
Application startup is coordinated through main.rs, while shared resources are initialized by state.rs.
Design Philosophy
The repository is organized around a clear separation of responsibilities.
- Networking lives in
handler/ - Shared data lives in
models/ - Queue backends live in
queue/ - Application state lives in
state.rs - Common errors live in
errors.rs - Application startup lives in
main.rs
This modular organization keeps individual source files focused, improves readability, simplifies testing, and makes future extensions easier without introducing unnecessary coupling between components.