srmilter
A Rust library for building mail filter (milter) daemons that integrate with Postfix.
Overview
srmilter implements the milter protocol to receive emails from Postfix, parse them, and return classification decisions (accept, reject, or quarantine). It provides a simple API for writing custom email classifiers.
Features
- Milter protocol implementation for Postfix integration
- Email parsing via
mail-parsercrate - Multithreading
- Spamhaus ZEN DNSBL lookup utilities
- systemd socket activation support (optional)
- Built-in CLI
Usage
-
Create a new binary crate:
-
Add srmilter as a dependency:
-
Edit
src/main.rsto create your milter binary (see example below).
Example
use ;
CLI Commands
The built-in CLI provides three subcommands:
# Run the milter daemon (default: 0.0.0.0:7044)
# Test classifier against an .eml file
Concurrency Options
- Default: Single-threaded, sequential processing
--threads N: Use up to N threads
systemd Deployment with Zero-Downtime Reloads
reload-proxy is a supervisor binary that enables zero-downtime reloads of a
srmilter-based daemon under systemd socket activation.
How it works
- systemd creates the listen socket and passes it to
reload-proxyas FD 3 (viaLISTEN_FDS). reload-proxyforwards the socket to the milter daemon via theSRMILTER_LISTEN_FD=3environment variable and spawns it as a child.- On
systemctl reload, systemd sendsSIGHUPtoreload-proxy, which spawns a new child instance (sharing the same listen socket), then sendsSIGINTto the old instance. - Both instances overlap briefly; the old one finishes its in-flight connections before exiting. No connections are dropped.
Unit files
mymilter.socket:
[Socket]
ListenStream=127.0.0.1:7044
[Install]
WantedBy=sockets.target
mymilter.service:
[Unit]
Requires=mymilter.socket
After=mymilter.socket
[Service]
Type=exec
ExecStart=/usr/local/bin/reload-proxy /usr/local/bin/mymilter daemon --threads 64
ExecReload=/bin/kill -HUP $MAINPID
TimeoutStopSec=15s
SyslogFacility=mail
SyslogIdentifier=mymilter
TimeoutStopSec should be set to the maximum time you are willing to wait
for in-flight connections to complete. On systemctl stop, systemd sends SIGTERM
to reload-proxy, which will then also terminate its children.
Triggering a reload
Postfix Configuration
Add to your Postfix main.cf:
smtpd_milters = inet:127.0.0.1:7044
License
Copyright © 2025 Donald Buczek buczek@molgen.mpg.de
Licensed under the European Union Public Licence (EUPL), Version 1.2. See the LICENSE file for details.