Skip to main content

Simple SMTP Server for debugging

Project description

dsmptd: A debugger SMTP server for Humans

Tests Status

dsmtpd is a small tool to help the developer without an smtp server

Python Support: Python 3.10, 3.11, 3.12, 3.13, 3.14

Usage

$ dsmtpd -p 1025 -i 127.0.0.1
2013-01-13 14:00:07,346 INFO: Starting SMTP server at 127.0.0.1:1025

Installation

For the installation, we recommend to use a virtualenv, it’s the easy way if you want to discover this package:

virtualenv ~/.envs/dsmtpd
source ~/.envs/dsmtpd/bin/activate

pip install dsmtpd

Command-Line Options

-p PORT, --port PORT

Specify the port to listen on. Default: 1025

-i INTERFACE, --interface INTERFACE

Specify the network interface to bind to. Default: 127.0.0.1 (loopback)

-d DIRECTORY, --directory DIRECTORY

Specify a Maildir directory to save incoming emails. Default: current directory

-s SIZE, --max-size SIZE

Maximum message size in bytes. Use 0 for no limit. Default: 33554432 (32 MiB)

--disable-smtputf8

Disable SMTPUTF8 extension for legacy SMTP client compatibility. Default: enabled

--version

Show program version and exit

-h, --help

Show help message and exit

Usage Examples

Start server with default settings (port 1025, localhost):

dsmtpd

Start server on custom port:

dsmtpd -p 2525

Bind to all interfaces:

dsmtpd -i 0.0.0.0 -p 25

Save emails to specific Maildir:

dsmtpd -d /path/to/maildir

Limit message size to 10 MB:

dsmtpd --max-size 10485760

Disable UTF-8 support for legacy clients:

dsmtpd --disable-smtputf8

Send a test email with swaks:

swaks --from sender@example.com --to recipient@example.com --server localhost --port 1025

Features

SMTPUTF8 Support

dsmtpd has built-in support for SMTPUTF8 (RFC 6531), which allows email addresses and content to contain UTF-8 characters. This feature is enabled by default and requires no configuration.

SMTPUTF8 enables:

  • Email addresses with international characters (e.g., 用户@例え.jp)

  • UTF-8 encoded message headers and body content

  • Full Unicode support in SMTP transactions

Example usage with UTF-8 email addresses:

swaks --from user@example.com --to 用户@例え.jp --server localhost --port 1025

This functionality is provided by the underlying aiosmtpd library and works transparently with all standard SMTP clients that support the SMTPUTF8 extension.

Disabling SMTPUTF8

If you need to test compatibility with legacy SMTP clients or reproduce encoding issues, you can disable SMTPUTF8:

dsmtpd --disable-smtputf8

When disabled, the server will not advertise SMTPUTF8 support and will only accept ASCII email addresses and content.

Exit Codes

dsmtpd uses specific exit codes to indicate the result of its execution.

Code

Meaning

Example

0

Success

Normal shutdown (e.g. user pressed Ctrl+C) or clean termination.

2

Invalid Maildir directory

The given path exists but does not contain the required subfolders: tmp, new, and cur.

Contributing

Clone the repository:

git clone git://github.com/matrixise/dsmtpd.git
cd dsmtpd

Development

The project includes a Makefile to simplify development tasks. It automatically manages a virtual environment and dependencies using Python from asdf or mise.

Quick Start

Set up your development environment:

make install-dev

This creates a .venv virtual environment and installs all development dependencies.

Available Make Targets

Development Workflow:

  • make install-dev - Set up development environment (creates venv and installs dependencies)

  • make test - Run tests with pytest (automatically installs dependencies if needed)

  • make lint - Check code quality with ruff linter

  • make lint-fix - Auto-fix linting issues and format code with ruff

  • make format - Format code with ruff format

  • make typecheck - Run mypy type checking

Build and Release:

  • make build - Build distribution packages

  • make check-dist - Verify distribution package integrity

Cleanup:

  • make clean - Remove all build artifacts and virtual environment

  • make clean-build - Remove only build artifacts (dist/, build/)

  • make clean-venv - Remove only the virtual environment

Workflow Tips

The Makefile uses smart dependency tracking. Running make test multiple times will only reinstall dependencies if requirements-dev.txt or setup.cfg have changed, making repeated test runs much faster.

To force a fresh installation of dependencies:

make install-dev

Running Tests

After setting up the development environment:

make test

Or directly with pytest:

.venv/bin/pytest

Code Quality & Pre-commit Hooks

The project uses prek to simplify pre-commit hook setup.

After installing development dependencies, set up pre-commit hooks:

prek install

This automatically installs git hooks that will:

  • Run ruff linter with auto-fix

  • Run ruff format for code formatting

  • Run mypy for type checking

You can also run quality checks manually:

make lint        # Check code quality
make lint-fix    # Auto-fix linting issues
make format      # Format code
make typecheck   # Run mypy type checking

The pre-commit hooks ensure code quality before commits, catching issues early and maintaining consistent code standards across all contributions.

Releasing

This section is for maintainers cutting a new release. The publication pipeline is automated via the publish GitHub Actions workflow and triggered by pushing a git tag prefixed with v.

Versioning policy

The project follows Semantic Versioning:

  • PATCH (e.g. 1.2.0 → 1.2.1) for bug fixes and internal/build-only changes that are invisible to users (e.g. dropping unnecessary build dependencies).

  • MINOR (e.g. 1.2.0 → 1.3.0) for new, backward-compatible features.

  • MAJOR (e.g. 1.2.0 → 2.0.0) for breaking changes.

Manual steps

  1. Bump the version in dsmtpd/__init__.py:

    __version__ = "X.Y.Z"

    This is the single source of truth: setup.cfg reads it via attr: dsmtpd.__version__.

  2. Add an entry at the top of CHANGES.rst:

    Version X.Y.Z
    -------------
    
    Released on YYYY-MM-DD.
    
    - Short summary of the change (#PR).
  3. Optionally validate the build locally:

    make build
    make check-dist
  4. Commit and push to main:

    git add dsmtpd/__init__.py CHANGES.rst
    git commit -m "Release version X.Y.Z"
    git push origin main
  5. Tag the release and push the tag:

    git tag vX.Y.Z
    git push origin vX.Y.Z

Automated steps (GitHub Actions)

Once the vX.Y.Z tag is pushed, the publish workflow will:

  • Run the test matrix on Python 3.10 → 3.14.

  • Verify that dsmtpd.__version__ matches the tag.

  • Build the package (python -m build) and validate it with twine check.

  • Publish to TestPyPI for pre-release validation.

  • Publish to PyPI (skipped automatically for tags containing pre-release suffixes such as -rc1).

  • Create the GitHub Release with auto-generated release notes.

Copyright 2013 (c) by Stephane Wirtel

dsmtpd Changelog

Here you can see the full list of changes between each dsmtpd release.

Version 1.2.1

Released on May 7th 2026.

  • Drop aiosmtpd and wheel from direct build dependencies (#41)

  • Fix SMTPUTF8 test to actually exercise non-ASCII email addresses (RFC 6531) (#40)

  • Document release process in README (#42)

  • Add Sviatoslav Sydorenko to AUTHORS (#43)

Version 1.2.0

Released on January 7th 2026.

Features:

  • Document SMTPUTF8 support (RFC 6531) - enabled by default via aiosmtpd (#32)

  • SMTPUTF8 allows UTF-8 email addresses, headers, and message content

  • Add --disable-smtputf8 CLI option to disable SMTPUTF8 extension for legacy client compatibility (#34)

Development improvements:

  • Add test coverage reporting with pytest-cov (#29)

  • Add code quality tools: ruff (linting/formatting) and mypy (type checking) (#29)

  • Add pre-commit hooks with prek for automated code quality checks (#31)

  • New make targets: lint, lint-fix, format, typecheck (#29)

  • Enhanced Makefile with automatic virtual environment management

  • Add smart dependency tracking to avoid unnecessary reinstallations during development

  • New make targets: install-dev, clean, clean-build, clean-venv

  • Makefile now uses Python from asdf/mise for consistent development environments

  • Significantly faster repeated test runs with timestamp-based dependency tracking

  • Add comprehensive tests for the debugging SMTP server (#8)

  • New integration tests for email reception, storage, and multipart email handling

  • Add tests for --version flag and --max-size option (#29)

  • Add test for SMTPUTF8 support verification (#32)

  • Add support for Python 3.14 (#25)

  • Replace deprecated license classifiers with SPDX license expression (#24)

  • GitHub Actions workflow now includes linting and type checking jobs (#29)

Version 1.1

Released on September 13th 2025.

  • Lower Python version requirement from 3.12 to 3.10 (#17)

  • Fix crash when directory exists but is not yet a valid Maildir with proper validation and repair functionality (#18)

  • Add exit codes documentation to README

  • Code formatting improvements with ruff

Version 1.0

Release on May 20th 2025.

  • Migration to aiosmtpd to Support Python >= 3.12 (#11, patch by Sebastian Wagner)

  • Add minimal tests for maildir check and importability

  • Add systemd service file (by Sebastian Wagner)

Version 0.3

Release on May 26th 2021.

  • Maildir capture: added early check (patch by Bernhard E. Reiter)

  • Remove the support of Docopt

  • Remove the support of Python 2.x (dead in 2020)

  • Support Python 3.6+

  • Improve the classifiers for PyPI

  • Migrate to PEP 517

  • Fix License into setup.py

  • Add tests for the CLI using argparse instead of docopt

Version 0.2

Release on January 21st 2013.

  • Allow to store the incoming emails in a maildir via the ‘-d’ argument

Version 0.1

Release on January 14th 2013.

  • Implement a basic server

  • Show the message in the log

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dsmtpd-1.2.1.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dsmtpd-1.2.1-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file dsmtpd-1.2.1.tar.gz.

File metadata

  • Download URL: dsmtpd-1.2.1.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dsmtpd-1.2.1.tar.gz
Algorithm Hash digest
SHA256 30092eee551c7812cb96443baac991eadb858267da54cf526d8fc90071bdc014
MD5 d62c09f5aa9f1aaafdb0056fee71a9f8
BLAKE2b-256 baf4d1e609bc13928797a35f0123fdeb61f406d4be249a7b031ab14bd4f9f9cf

See more details on using hashes here.

Provenance

The following attestation bundles were made for dsmtpd-1.2.1.tar.gz:

Publisher: publish.yml on matrixise/dsmtpd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dsmtpd-1.2.1-py3-none-any.whl.

File metadata

  • Download URL: dsmtpd-1.2.1-py3-none-any.whl
  • Upload date:
  • Size: 10.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dsmtpd-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 41a8000e3d8a276ee14be45349c9fd3d3907c7740151c0431bf9214065734506
MD5 bd4892d895e9f2d409e6ba97ff4321bb
BLAKE2b-256 6c8c7898c42f2a16a07ad96a1743e82295a383ccf14640d46ebee7ab90a39d8f

See more details on using hashes here.

Provenance

The following attestation bundles were made for dsmtpd-1.2.1-py3-none-any.whl:

Publisher: publish.yml on matrixise/dsmtpd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page