The purpose of this Ansible role is to fulfill my demands on my own mail server:
- Supports openSUSE Leap 15.5
- Orchestration of Postfix (MTA), Dovecot (MDA) and Rspamd
- Postfix uses Dovecot for authentication (SMTP AUTH through Dovecot SASL)
- No databases for configuration, just plain files
- Mails to specific addresses can be relayed to another MTA
- Mails to specific addresses can be rejected
- Outgoing mails are DKIM signed
- Relayed mails are ARC signed
- Catch-all accounts can be configured
- Multiple domains are supported
- Sieve rules can be used
- Spam
- Spam with a high score is rejected
- Spam detection can be disabled for specific senders (addresses or domains)
- Potential spam is not automatically delivered into a Spam folder (of course a customa Sieve rule can be used)
- Potential spam is greylisted
- Spam can be learnt by moving the mail into a special IMAP folder
- Spam can be learnt by applying the Junk flag, which is used by Thunderbird
- Ham can be learnt by moving the mail into a special IMAP folder
- Ham can be learnt by applying the NonJunk flag, which is used by Thunderbird
- Ham can be learnt by marking the mail with a green flag in the iOS Mail App
- Antivirus
- Integration of ClamAV
- Integration of Fangfrisch
- Integration of VirusTotal.com
- Infected mails are rejected
- Nice reports (rspamd WebUI is sufficient for me)
- Nearly all requirements are covered by tests
- Tests are executed by a CI system
This role is available via Ansible Galaxy under the name chkpnt.mailserver
. It can be installed with
$ ansible-galaxy install chkpnt.mailserver
and used within a playbook like
---
- hosts: server1
remote_user: root
roles:
- role: chkpnt.mailserver
vars:
mail_domain: example.com
mail_hostname: server1.example.com
mail_mailname: server1.example.com
mail_mailbox_domains:
- example.com
- example.net
- example.org
mail_ssl:
certificate: '/etc/ssl/servercerts/example.com.crt.pem'
private_key: '/etc/ssl/private/example.com.privkey.pem'
generate_certificate_for_test: yes
generate_safe_primes_for_dh: yes # https://www.openssl.org/news/secadv/20160128.txt
mail_dkim_keys:
- { domain: example.com, selector: 'key1', private_key: '/var/lib/rspamd/dkim/example.com.key1.key' }
- { domain: example.org, selector: 'key1', private_key: '/var/lib/rspamd/dkim/example.org.key1.key' }
- { domain: example.net, selector: 'key1', private_key: '/var/lib/rspamd/dkim/example.net.key1.key' }
# Hash can be computated with doveadm.
# I recommend using Blowfish as the hashing schema, the ideal number of rounds depends on your system.
# > doveadm pw -s BLF-CRYPT -r 10
mail_accounts:
- { user: 'john.doe@example.com', password: '{BLF-CRYPT}$2y$10$6W9VYuRklwLg8y2UoP6YHuK5Q8g7g.LOJdSa7K4CgoVMmARNYMVMK' } # Password: changeme
- { user: 'jane.doe@example.com', password: '{BLF-CRYPT}$2y$10$wZtIn5uHAsbsMgMmOdBdU.qbRgrQxfeej65G63aUxMaDNEHfb8P2e' } # Password: changeme
mail_mailboxes:
- { name: 'john.doe@example.com', path: '/srv/mail/john' }
- { name: 'jane.doe@example.com', path: '/srv/mail/jane' }
mail_aliases:
# a self-referencing alias is needed if the mail_transports is used
- { for: 'gmail@example.com', destination: 'gmail@example.com' }
# normal aliases
- { for: 'wedding@example.com', destination: 'family@example.com' }
- for: 'family@example.com'
destination:
- 'john.doe@example.com'
- 'jane.doe@example.com'
# Catch-Alls:
- { for: '@example.com', destination: 'john.doe@example.com' }
- { for: '@example.org', destination: 'john.doe@example.com' }
- { for: '@example.net', destination: 'john.doe@example.com' }
mail_recipient_restrictions:
- for: 'reject@example.com'
action: 'REJECT This address is not supposed to receive mails!'
mail_transports:
- for: 'gmail@example.com'
nexthop: 'smtp:gmail.com'
mail_spam:
greylisting_delay: 5min
thresholds: # Requirement: greylist < add_header < reject
greylist: 4
add_header: 6
reject: 15
controller:
# Controller worker is used to manage rspamd stats, to learn rspamd and to serve WebUI.
# https://rspamd.com/doc/workers/controller.html
# If you access the WebUI from localhost, you won't be asked for the password as localhost is a "secure_ip"
# > rspamadm pw
password: '$2$c75qgo1b8brudgq7wokg8wxr5qiby84p$ye6ss3ymc4h4u4swk3fhx3ph7jesahqrzw8kkxwhyfb14g4rkfhb' # Password: changeme
bind_socket: 'localhost:11334'
# Regexps are supported
allowlist_domain:
- foobar.test
allowlist_email:
- /.*@important.test/
The defaults of the variables are defined in defaults/main.yml. All variables refering to example.com
or similar are expected to be explicitly declared in your playbook.
The playbook tests/testfixtures/vms/sut.yml used by the tests is a good example, too.
I recommend to set up a Python environment using pipenv. On macOS, pipenv can be installed using Homebrew:
$ brew install pipenv
To use the Python environment with pipenv, just enter the following commands:
$ pipenv install --dev
$ pipenv shell
In order to run the tests, VirtualBox and Vagrant are required. On macOS, these dependencies can be installed using Homebrew as well:
$ brew install --cask virtualbox
$ brew install --cask vagrant
For managing your Vagrant virtual machines, I can recommend the use of Vagrant-Manager, a small utility app for the menu bar.
$ brew install --cask vagrant-manager
Additional information about the tests can be found in the corresponding document.
Apache-2.0