A complete and secure mail server with Postfix, Dovecot and Rspamd on the latest Debian.
1.8K
This container image creates a secure and fast mail server. The login details, domains and email addresses (including aliases) are loaded via a MariaDB server, which must be located externally. The Database configuration is very simple and is also documented in this description.
Why this image? You can invest a lot of time installing a mail server, but after a while, the operating system becomes outdated, and the configurations of the individual services have changed again. Essentially, you're always starting from scratch and never know if everything is configured correctly and securely. There are thousands of ways to configure a mail server, but in reality, you only use a few of the same settings. These "simple" configurations are set in this image via environment variables, while the more complex ones that ensure security remain in the background. That's the reason for this image... you can update the operating system at any time and quickly reactivate and use a secure mail server with this image without having to worry about which service settings have changed again.
| Major | Minor | Patch | Debian | Dovecot | Postfix | Rspamd | Redis | Additional Information |
|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 0 | Trixie (13.2) | 2.4.1-4 | 3.10.5 | x | x | (nothing) |
| 1 | 1 | 1 | Trixie (13.2) | 2.4.1-4 | 3.10.5 | x | x | Cleaned Imap Folders |
| 1 | 2 | 0 | Trixie (13.3) | 2.4.1-4 | 3.10.5 | x | x | New Trixie Version and add Configuration Values |
| 1 | 3 | 0 | Trixie (13.4) | 2.4.1-4 | 3.10.5 | x | x | New Trixie Version and original Rspamd Repository |
| 1 | 4 | 0 | Trixie (13.6) | 2.4.1-4 | 3.10.13 | 4.1.5 | 8.10.1 | New Trixie Version and original Redis Repository |
At each startup, the configuration is rewritten using any existing environment variables. Unset environment variables are assigned default values, which can be found in the table below. If the configuration volume for Postfix, Dovecot and Rspamd is passed from the host system, a touch DONOTOVERRIDE file can be used to protect the configuration from being overwritten if you want to store a completely custom configuration.
The use of a certificate is mandatory. If none is available at the start, a dummy certificate will be issued for one year.
Postfix security is configured as follows: Port 25/tcp (smtp): Server-to-server connections, as well as connections within the local network (MAIL_NETWORKS Environment Variable) and password-authorized users, are permitted. Port 465/tcp (smtps): Only Client connections within the local network (MAIL_NETWORKS Environment Variable) and password-authorized users are permitted. Port 587/tcp (submission): Only Client connections within the local network (MAIL_NETWORKS Environment Variable) and password-authorized users are permitted.
Emails in the Junk and Trash folders are automatically deleted when they are 60 days old.
| Variable | Default | Server | Description |
|---|---|---|---|
| MAIL_HOSTNAME | mail.example.com | Postfix Dovecot | The internet hostname of this mail system |
| MAIL_NETWORKS | Postfix Rspamd | The list of trusted IP (comma seperated) | |
| MAIL_SIZELIMIT | 52428800 | Postfix Rspamd | Max incoming message size limit in bytes |
| MAIL_CONNLIMIT | 0 | Postfix | The maximum number of connections an client is allowed to establish within 60 seconds (default: no limit) |
| MAIL_MESSLIMIT | 0 | Postfix | The maximum number of message delivery requests that an SMTP client may make within 60 seconds (default: no limit) |
| MAIL_IMAPLIMIT | 50 | Dovecot | The maximum number of IMAP connections allowed for a user from each IP address |
| MAIL_IPv4 | true | Postfix Dovecot | Using IPv4 (set to false to disable it |
| MAIL_IPv6 | true | Postfix Dovecot | Using IPv6 (set to false to disable it |
| DB_HOST | host.containers.internal | Postfix Dovecot | Host Server Name or IP Address from the Database Server |
| DB_NAME | maildb | Postfix Dovecot | Name of the Database |
| DB_USER | mailusr | Postfix Dovecot | User Name for the Database connect |
| DB_PASSWORD | VerySecure0815 | Postfix Dovecot | Password for the Database connect |
| CERT_FILE | mail.crt | Postfix Dovecot | Certificate File |
| CERT_KEY | mail.key | Postfix Dovecot | Certificate Key File |
| Image Directory | Using for |
|---|---|
| /opt/dovecot/conf | Configuration Directory for Dovecot |
| /opt/dovecot/logs | Logging Directory for Dovecot |
| /opt/postfix/conf | Configuration Directory for Postfix |
| /opt/postfix/logs | Logging Directory for Postfix |
| /opt/rspamd/conf | Configuration Directory for Rspamd |
| /opt/rspamd/logs | Logging Directory for Rspamd |
| /opt/cert | Certificate Directory |
| /opt/vmail | Maildir and Sieve Directories - UID#5000 GID#5000 |
The image does not have its own logrotate function. It is recommended to monitor the log directories via the host using logrotate to prevent the filesystem from filling up.
Example of the structure of the mail and sieve directory:
e-mail: [email protected]
+ /opt/vmail/
|
+--+ mailboxes/
| |
| +--+ example.com/
| | |
| | +--+ test/
| | | |
| | | + Maildir/
| | | |
| | | + ... Imap Dovecot Structur
| | |
| | +--+ ...
| |
| +--+ ...
|
+--+ sieve/
|
+--+ example.com/
| |
| +--+ test/
| | |
| | + ... Sieve Dovecot Structur
| |
| +--+ ...
|
+--+ ...
The domains should be created manually. Everything else is done automatically by the system. Please ensure that the entire directory, including all files, has the correct permissions, user ID 5000, and group ID 5000.
| Port | Using for |
|---|---|
| 143 | imap (dovecot) |
| 993 | imaps (dovecot) |
| 25 | smtp (postfix) |
| 465 | smtps (postfix) |
| 587 | submission (postfix) |
| 4190 | sieve (dovecot) |
| 11334 | webfrontend (rspamd) |
Rspamd is very complex and includes some additional configurations.
RSPAMD_ENABLE=true
Enabling Rspamd. To activate it, set the environment variable to true (default). If you do not want to use Rspamd, set the environment variable to false. It is definitely recommended to use Rspamd.
RSPAMD_PASSWORD=VerySecure0815
The web interface for Rspamd can be accessed via port 11334. However, it must be ensured that access is password-protected. This parameter allows you to set the password.
RSPAMD_TYP=balanced
For Rspamd to detect spam emails, various parameters are necessary to specify the desired accuracy. However, there is a problem: the more accurate the detection, the higher the probability of false positives. Possible entries for this environment variable are: aggressive, balanced (default) and conservative.
RSPAMD_USE_UNBOUND=false
Rspamd queries the DNS very frequently. Your provider might limit these queries. If so, you can use a custom DNS resolver in your container by setting the environment variable to true (default: false). This resolver is configured to query the Google and Cloudflare resolvers alternately and unfiltered over an encrypted TLS connection. For this to work, it's crucial that your container has access to the internet via port 853/tcp.
RSPAMD_USE_CLAMAV=false
ClamAV is also present in the container, but is only started and used by Rspamd if it is enabled. A ClamAV database dated January 2026 is installed by default. The host system can use a cron job to call the freshclam update client in the container, which then updates the database. Here is an podman example cron job entry for the mail container:
0 5 * * 1 podman exec -u clamav mail /usr/bin/freshclam --config-file=/opt/clamav/conf/freshclam.conf --foreground --quiet
RSPAMD_USE_DKIM=false
Rspamd offers the option to digitally sign outgoing emails (DKIM). If you wish to use this feature, you can enable it by setting the environment variable to true (default: false). However, since not all domains automatically have the header added, the directory /opt/rspamd/dkim MUST be connected, as this is where the key files are located. Please refer to the rspamd documentation for detailed configuration instructions. Important: Only the key needs to be in the directory. The script creates the Rspamd configuration based on the filename: [domain]_[selector].key. Here is an example filename:
Filename:
example.com_sel001.key: This is for the Domainexample.comand the Selectorsel001.
The potential users and their associated email domains/addresses/aliases are queried via a MariaDB database. The database must be present, populated, and connected from the start, as the container queries the domains at startup to automatically create the corresponding directories for Maildir and Sieve. Here are the tables required for this:
##
## Create new sql tables
##
# Information: create database vmaildb CHARACTER SET 'utf8';
# Information: grant select on vmaildb.* to 'vmail'@'%' identified by 'vmaildbpass';
use vmaildb;
DROP TABLE IF EXISTS `domains`;
CREATE TABLE `domains` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`domain` varchar(255) NOT NULL,
`enabled` boolean DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY (`domain`)
);
DROP TABLE IF EXISTS `accounts`;
CREATE TABLE `accounts` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(64) NOT NULL,
`domain` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`quota` int unsigned DEFAULT '0',
`enabled` boolean DEFAULT '0',
`sendonly` boolean DEFAULT '0',
PRIMARY KEY (id),
UNIQUE KEY (`username`, `domain`),
FOREIGN KEY (`domain`) REFERENCES `domains` (`domain`)
);
DROP TABLE IF EXISTS `aliases`;
CREATE TABLE `aliases` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`source_username` varchar(64),
`source_domain` varchar(255) NOT NULL,
`destination_username` varchar(64) NOT NULL,
`destination_domain` varchar(255) NOT NULL,
`enabled` boolean DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY (`source_username`, `source_domain`, `destination_username`, `destination_domain`),
FOREIGN KEY (`source_domain`) REFERENCES `domains` (`domain`)
);
DROP TABLE IF EXISTS `tlspolicies`;
CREATE TABLE `tlspolicies` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`domain` varchar(255) NOT NULL,
`policy` enum('none', 'may', 'encrypt', 'dane', 'dane-only', 'fingerprint', 'verify', 'secure') NOT NULL,
`params` varchar(255),
PRIMARY KEY (`id`),
UNIQUE KEY (`domain`)
);
Here's a small example of how to fill in the tables:
insert into domains set domain = "example.com", enabled = true;
insert into accounts username = 'test', domain = 'example.com', password = '{SHA512-CRYPT}$6$RPda7/UpvubYBg3o$wSOlCVRIFVk7aeP.ftBrfSMDX4CcD.ce21CuukztAtXGbLmaHoZZOyMp8rRs0VELlcVJ9K1dykMH66x/moFnm0', quota = 2048, enabled = true, sendonly = false;
insert into aliases source_username = 'test', source_domain = 'example.com', destination_username = 'test', destination_domain = 'example.com', enabled = true;
The password can be generated via the mail container in the console (test password: test123):
root@mail:/#
root@mail:/# doveadm pw -s SHA512-CRYPT
Enter new password:
Retype new password:
{SHA512-CRYPT}$6$RPda7/UpvubYBg3o$wSOlCVRIFVk7aeP.ftBrfSMDX4CcD.ce21CuukztAtXGbLmaHoZZOyMp8rRs0VELlcVJ9K1dykMH66x/moFnm0
root@mail:/#
Content type
Image
Digest
sha256:5454456de…
Size
292.6 MB
Last updated
about 1 month ago
docker pull skoep/mail