rmail

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

Prerequisites

Installation from Source

git clone <repo> rmail
cd rmail

There is no build step. The server runs directly from the source tree.

Optional: Install as a Systemd Service

sudo python3 run.py install

This writes a systemd unit file at /etc/systemd/system/rmail.service, enables the service, and starts it. The service restarts automatically on failure. Use the Makefile targets for day-to-day management:

make start
make stop
make restart
make status
make logs

To remove the service:

sudo python3 run.py uninstall

Configuration

Generate a default config.json:

python run.py init

Open config.json and set at minimum:

TLS certificates are auto-generated on first startup and stored under {mail_root}/tls/. To use a CA-signed certificate, set tls.cert_file and tls.key_file in config.json before starting.

Starting the Server

python run.py

On first run, if config.json does not exist, defaults are written automatically. The server starts SMTP, IMAP, and the Exchange API listeners, then waits for connections.

Ports 25, 143, 465, 587, and 993 require elevated privileges. Run with sudo or grant the Python binary CAP_NET_BIND_SERVICE.

Creating Users

make user

You will be prompted for an email address (e.g. alice@example.com) and a password. The user directory and default mailboxes (INBOX, Sent, Drafts, Trash) are created immediately.

Additional user management commands:

make passwd       # change a user's password
make deluser      # delete a user
make listusers    # list all users for a domain

Verifying the Installation

sudo python3 run.py diagnose

The diagnostic tool runs 8 phases covering configuration, user management, storage, SMTP, delivery, IMAP, the Exchange API, and cleanup. A passing run reports 0 failures and 0 warnings.

Migrating from a Previous Version

If upgrading from a version that stored messages using index.json and msg-{uid}.eml files:

python run.py migrate

Each mailbox is converted to status.json plus shard directories with flag-encoded filenames. The original index.json is preserved as index.json.migrated.