rmail

Production-grade mail server stack in pure Python 3 asyncio — SMTP, IMAP4rev1, and Exchange REST API.

Overview

All configuration is stored in config.json at the working directory. Generate a default file with:

python run.py init

The server reads config.json at startup. A SIGHUP signal triggers a live reload without restarting listeners.

If config.json is absent at startup, default values are written automatically. The default hostname is mail.example.com — always set this to your actual FQDN.

Top-Level Settings

KeyDefaultDescription
hostnamemail.example.comServer FQDN, used in SMTP banners and autoconfig responses.
mail_root./mailstoreRoot directory for all user data and TLS certificates.
domains["example.com"]List of accepted mail domains (case-insensitive at runtime).
log_levelINFOPython logging level: DEBUG, INFO, WARNING, ERROR, CRITICAL.

SMTP Settings (smtp.*)

KeyDefaultDescription
smtp.host0.0.0.0Bind address for all SMTP listeners.
smtp.port25SMTP port for inbound delivery (unauthenticated external relay accepted).
smtp.submission_port587Authenticated submission port (STARTTLS required for AUTH when TLS configured).
smtp.smtps_port465Implicit TLS SMTP port (activated when TLS is configured).
smtp.max_message_size52428800Maximum message size in bytes (50 MB). Enforced via SIZE extension.
smtp.max_recipients50Maximum RCPT TO recipients per transaction. Returns 452 on excess.
smtp.max_connections100Maximum simultaneous SMTP connections.
smtp.max_messages_per_connection50Maximum messages per SMTP session before disconnect.

IMAP Settings (imap.*)

KeyDefaultDescription
imap.host0.0.0.0Bind address for IMAP listeners.
imap.port143IMAP4rev1 plain-text port (STARTTLS available when TLS configured).
imap.imaps_port993IMAPS implicit TLS port (activated when TLS is configured).
imap.max_connections100Maximum simultaneous IMAP connections.

Exchange API Settings (exchange_api.*)

KeyDefaultDescription
exchange_api.host0.0.0.0Bind address for HTTP API listeners.
exchange_api.port9002HTTP API port.
exchange_api.secure_port9003HTTPS API port (activated when TLS is configured).
exchange_api.token_secretauto-generatedHMAC-SHA256 key for JWT signing. Set explicitly for multi-process deployments so tokens are valid across processes.

TLS Settings (tls.*)

KeyDefaultDescription
tls.cert_filenullPath to PEM certificate. When null, a self-signed cert is auto-generated in {mail_root}/tls/cert.pem.
tls.key_filenullPath to PEM private key. When null, auto-generated alongside the cert.
When TLS is configured (cert_file is set or auto-generated), AUTH is hidden from cleartext SMTP EHLO and IMAP CAPABILITY responses. Clients must negotiate STARTTLS before authentication credentials are accepted. This behaviour is intentional and cannot be disabled independently of TLS.
Auto-generated certificates are self-signed and suitable for testing or internal use only. For production, set tls.cert_file and tls.key_file to paths of CA-signed certificates before starting the server.

Delivery Settings (delivery.*)

KeyDefaultDescription
delivery.workers4Number of async worker coroutines in the delivery queue. Increase for high-volume inbound workloads.

Rate Limiting (rate_limit.*)

Per-IP sliding-window rate limiting applied to SMTP connections. Enabled by default.

KeyDefaultDescription
rate_limit.enabledtrueEnable or disable rate limiting globally.
rate_limit.connection_rate20Maximum connections per IP within connection_period.
rate_limit.connection_period60Period in seconds for connection rate window.
rate_limit.message_rate30Maximum messages per IP within message_period.
rate_limit.message_period60Period in seconds for message rate window.
rate_limit.recipient_rate100Maximum recipients per IP within recipient_period.
rate_limit.recipient_period60Period in seconds for recipient rate window.
rate_limit.auth_failure_limit5Authentication failures before IP lockout.
rate_limit.auth_failure_lockout600Lockout duration in seconds after auth failure limit is reached.
rate_limit.max_concurrent_per_ip10Maximum simultaneous connections from a single IP.
rate_limit.whitelist["127.0.0.1", "::1"]IPs exempt from all rate limiting.
rate_limit.max_tracked_ips10000Maximum number of IPs tracked in memory.
rate_limit.cleanup_interval300Seconds between expiry cleanup of stale IP records.
Ensure 127.0.0.1 remains in rate_limit.whitelist when running diagnostics or tests from localhost, otherwise test connections will be rate-limited and the diagnostic suite will fail.

Example config.json

{
  "hostname": "mail.example.com",
  "mail_root": "./mailstore",
  "domains": ["example.com"],
  "log_level": "INFO",
  "smtp": {
    "host": "0.0.0.0",
    "port": 25,
    "submission_port": 587,
    "smtps_port": 465,
    "max_message_size": 52428800,
    "max_recipients": 50,
    "max_connections": 100,
    "max_messages_per_connection": 50
  },
  "imap": {
    "host": "0.0.0.0",
    "port": 143,
    "imaps_port": 993,
    "max_connections": 100
  },
  "exchange_api": {
    "host": "0.0.0.0",
    "port": 9002,
    "secure_port": 9003,
    "token_secret": null
  },
  "delivery": {
    "workers": 4
  },
  "tls": {
    "cert_file": null,
    "key_file": null
  },
  "rate_limit": {
    "enabled": true,
    "connection_rate": 20,
    "connection_period": 60,
    "message_rate": 30,
    "message_period": 60,
    "auth_failure_limit": 5,
    "auth_failure_lockout": 600,
    "max_concurrent_per_ip": 10,
    "whitelist": ["127.0.0.1", "::1"]
  }
}