Easily set up a Mail Server with Roundcube Webmail using Docker β without any hassle.
Easy Mailstack is a simple Docker-based solution to deploy a fully functional mail server along with the Roundcube webmail interface in just a few steps. Perfect for developers, small businesses, or anyone who needs an email solution without complex configurations.
- Mail server powered by Postfix/Dovecot.
- Roundcube webmail pre-configured for easy access.
- Support for custom SSL certificates.
- Persistent storage for mail data, logs, and PostgreSQL database.
- Simple script to create email accounts.
- Management CLI (
easy_mailstack.sh) for listing, deleting, deactivating accounts, and managing quotas. - Rspamd daily send rate limiting for authenticated SMTP users (
1000 emails/dayby default, configurable toN emails/day).
.
βββ certs/ # SSL certificates
βββ compose.yaml # Your main docker-compose file (ignored in Git)
βββ compose.yaml_example # Example compose file
βββ config/ # Custom mail server configs
β βββ postfix-main.cf # Persistent Postfix overrides
β βββ rspamd/override.d/ # Rspamd override configs, including daily send rate limit
βββ config.inc.php # Roundcube config (ignored in Git)
βββ config.inc.php_example # Example Roundcube config
βββ create_email.sh # Script to create email accounts
βββ easy_mailstack.sh # Management CLI for email accounts
βββ setup_dkim.sh # Persistent DKIM helper
βββ mail-data/ # Mail data storage (ignored in Git)
βββ mail-logs/ # Log files (ignored in Git)
βββ mail-state/ # Mail state data (ignored in Git)
βββ postgresql/ # Database data (ignored in Git)
- Docker and Docker Compose
- A domain name (e.g.,
mail.example.com) - Open ports:
25,143,587,993,80,443
-
Clone the repository
git clone https://github.com/your-username/easy-mailstack.git cd easy-mailstack -
Copy example configuration files
cp .env-mailserver.example .env-mailserver cp compose.yaml_example compose.yaml cp config.inc.php_example config.inc.php
-
Edit the
.env-mailserverfile- Set your domain name
- Configure mail settings (hostname, users, etc.)
-
Start the containers
docker compose up -d
-
Access Roundcube
- Open
https://mail.yourdomain.com - Login with your email credentials
- Open
By default you need to cd into the project directory to run ./easy_mailstack.sh. To make it available as a command from anywhere on your system, follow these steps:
Create a symbolic link in /usr/local/bin:
# Make sure the script is executable
chmod +x /path/to/easy-mailstack/easy_mailstack.sh
# Create a symlink with a shorter name
sudo ln -sf /path/to/easy-mailstack/easy_mailstack.sh /usr/local/bin/easy-mailstackNow you can run it from anywhere:
easy-mailstack --list-email
easy-mailstack --set-quota --email user@example.com --size 1GAdd the project directory to your shell's PATH:
# For bash (~/.bashrc)
echo 'export PATH="/path/to/easy-mailstack:$PATH"' >> ~/.bashrc
source ~/.bashrc
# For zsh (~/.zshrc)
echo 'export PATH="/path/to/easy-mailstack:$PATH"' >> ~/.zshrc
source ~/.zshrcAdd an alias to your shell config:
# For bash (~/.bashrc) or zsh (~/.zshrc)
echo "alias easy-mailstack='/path/to/easy-mailstack/easy_mailstack.sh'" >> ~/.bashrc
source ~/.bashrcNote: Replace
/path/to/easy-mailstackwith your actual project path (e.g./root/docker_app/easy-mailstack).
Use the included script:
# With a 1G quota and 1000 emails/day SMTP send limit
./create_email.sh user@example.com password 1G 1000
# With a 1G quota and no rate-limit change
./create_email.sh user@example.com password 1G
# With unlimited quota (default)
./create_email.sh user@example.com password 0
./create_email.sh user@example.com password # 0 is the default
# Interactive mode (prompts for email, password, quota, and optional daily send limit)
./create_email.shQuota sizes: use M for MB, G for GB, T for TB, or 0 for unlimited.
Daily send limits are global per authenticated SMTP user. Passing the fourth argument updates the Rspamd limit for all authenticated users.
easy-mailstack --list-emaileasy-mailstack --domain example.com --list-emaileasy-mailstack --send-test --email recipient@example.com --from sender@example.comPermanently removes the account (with confirmation prompt):
easy-mailstack --delete-email --email user@example.comDisables sending and receiving without deleting the account or its data:
easy-mailstack --deactivate-email --email user@example.comeasy-mailstack --deactivate-email --email user@example.com --reactivateSet a storage limit (use M for MB, G for GB, T for TB):
easy-mailstack --set-quota --email user@example.com --size 1G
easy-mailstack --set-quota --email user@example.com --size 500Measy-mailstack --del-quota --email user@example.comDo not edit /etc/opendkim or run postconf -e inside the running container for permanent changes. Those edits can disappear after container recreation. This project mounts ./config to /tmp/docker-mailserver, so persistent mailserver config belongs under ./config.
If DKIM was already fixed manually in the running container and DNS already points to that public key, copy the live private key into persistent config:
easy-mailstack --persist-live-dkim --domain laurenscodes.space
docker compose restart mailserverThat keeps the current DNS TXT record valid and configures Rspamd to sign using:
config/opendkim/keys/<domain>/mail.private
config/rspamd/override.d/dkim_signing.conf
For a fresh DKIM setup, generate a new persistent key and then add the printed DNS TXT record:
easy-mailstack --setup-dkim --domain laurenscodes.space
easy-mailstack --show-dkim-dns --domain laurenscodes.space
docker compose restart mailserverOutbound SMTP TLS is persisted in:
config/postfix-main.cf
It enables opportunistic STARTTLS for outbound delivery:
smtp_tls_security_level = may
Sets the Rspamd authenticated-user daily send limit. The default is 1000 emails/day; use any positive integer for N emails/day:
easy-mailstack --set-rate-limit --limit 1000
easy-mailstack --set-rate-limit --limit 250Check or remove the generated Rspamd override:
easy-mailstack --show-rate-limit
easy-mailstack --del-rate-limitAfter changing the rate limit, restart the mailserver:
docker compose restart mailserverVerify Rspamd sees the config:
docker exec -it mailserver rspamadm configdump ratelimitTo use quota management, you must enable quotas in your mailserver configuration:
-
Add to your
.env-mailserverfile:ENABLE_QUOTAS=1
-
Restart the mailserver:
docker compose down && docker compose up -d -
Verify quotas are working:
easy-mailstack --list-email
You should see quota usage like
( 881K / 1G ) [8%]instead of( 881K / ~ ) [0%].
Rate limiting is enabled through Docker Mailserver's built-in Rspamd support. The repository includes:
config/rspamd/override.d/ratelimit.conf
Default behavior:
1000 emails/dayper authenticated SMTP user.- Recipient-counted: one message to 10 recipients consumes 10 from the bucket.
- Uses Rspamd token-bucket behavior, so the limit refills continuously over one day.
- Applies to authenticated outbound SMTP users through
selector = "user.lower".
Recommended .env-mailserver settings:
ENABLE_RSPAMD=1
ENABLE_RSPAMD_REDIS=1
RSPAMD_CHECK_AUTHENTICATED=1
RSPAMD_GREYLISTING=0
ENABLE_OPENDKIM=0
ENABLE_OPENDMARC=0
ENABLE_POLICYD_SPF=0
ENABLE_AMAVIS=0
MAIL_RATE_LIMIT_PER_DAY=1000MAIL_RATE_LIMIT_PER_DAY is used by the helper scripts as the default value; Rspamd uses config/rspamd/override.d/ratelimit.conf.
DKIM signing is handled by Rspamd when these settings are used. Keep OpenDKIM disabled to avoid milter conflicts.
Change the limit to any N emails/day:
easy-mailstack --set-rate-limit --limit N
docker compose restart mailserverExample:
easy-mailstack --set-rate-limit --limit 500
docker compose restart mailserver- Place your SSL certificates in the
certs/directory. - Update the
compose.yamlfile to map them correctly.
Edit .env-mailserver:
DOMAIN=example.com
HOSTNAME=mail.example.com
POSTMASTER_ADDRESS=postmaster@example.com
ENABLE_QUOTAS=1
ENABLE_RSPAMD=1
ENABLE_RSPAMD_REDIS=1
RSPAMD_CHECK_AUTHENTICATED=1
MAIL_RATE_LIMIT_PER_DAY=1000
# Add more as neededStart the stack:
docker compose up -dStop the stack:
docker compose downCheck logs:
docker compose logs -fCreate new email with 1G quota:
./create_email.sh newuser@example.com strongpassword 1GCreate new email and set daily send limit to 1000 emails/day:
./create_email.sh newuser@example.com strongpassword 1G 1000Create new email with unlimited quota:
./create_email.sh newuser@example.com strongpassword 0This project is licensed under the MIT License.
Feel free to open issues or submit pull requests to improve this project.