This service acts as a TCP lookup table for Postfix to dynamically route emails based on the MX records of the destination domain. It allows routing decisions to be made based on pattern matching against MX hostnames.
When Postfix needs to deliver an email, it queries this service with the destination domain. The service:
- Looks up the domain's MX records
- Compares them against the defined patterns in the configuration file
- If a match is found, it returns the corresponding relay server
- If no match is found, Postfix will use its default transport (usually direct delivery)
This can be useful to, for example, optimize email delivery for domains that use the Microsoft mail infrastructure by routing these emails through specialized third-party SMTP relays with established sender reputations.
The service uses substring matching for MX patterns, not exact matching. This means:
- Patterns like
protection.outlook.comwill match MX records such ashotmail-com.olc.protection.outlook.com - You can use shorter, more generic patterns to match multiple similar MX records
- The first pattern that matches any part of an MX record will be used
- Patterns are checked in the order they appear in the configuration file
Please be aware that patterns are not matched against recipient domain but the MX records of that domain!
- Python 3.6 or higher
- Clone this repository:
$ git clone https://github.com/filidorwiese/postfix-mx-pattern-router.git /usr/local/bin/postfix-mx-pattern-router
$ cd /usr/local/bin/postfix-mx-pattern-router- Install dependencies:
$ pip install -r requirements.txtOr use package manager from your distribution.
- Create the configuration file to define your MX patterns:
$ nano /etc/postfix/postfix-mx-pattern-router.confExample configuration:
protection.outlook.com relay:[office365-relay.example.com]:587
mx.microsoft relay:[office365-relay.example.com]:587
icloud.com relay:[icloud-relay.example.com]:587
For security reasons, it's recommended to run the service under a dedicated system user with minimal privileges:
# Create a system user and group without login capabilities
$ groupadd --system postfix-mx-pattern-router
$ useradd --system --no-create-home --shell /usr/sbin/nologin -g postfix-mx-pattern-router postfix-mx-pattern-routerCreate a systemd unit file to run the service as a daemon:
$ nano /etc/systemd/system/postfix-mx-pattern-router.serviceAdd the following content:
[Unit]
Description=Postfix MX Pattern Router Service
After=network.target
[Service]
ExecStart=/usr/local/bin/postfix-mx-pattern-router/postfix-mx-pattern-router.py -c /etc/postfix/postfix-mx-pattern-router.conf -p 10099 --cache-ttl 3600
Restart=on-failure
User=postfix-mx-pattern-router
Group=postfix-mx-pattern-router
StandardOutput=journal
StandardError=journal
SyslogIdentifier=postfix-mx-pattern-router
SyslogFacility=mail
[Install]
WantedBy=multi-user.targetEnable and start the service:
$ systemctl enable postfix-mx-pattern-router
$ systemctl start postfix-mx-pattern-routerCheck the status:
$ systemctl status postfix-mx-pattern-routerAdd the following to your Postfix configuration (/etc/postfix/main.cf):
transport_maps = tcp:[127.0.0.1]:10099
Then reload Postfix.
You can test the service directly from the command line using netcat (nc) to simulate Postfix queries:
$ echo "get user@outlook.com" | nc 127.0.0.1 10099
200 relay%3A%5Boffice365-relay.example.com%5D%3A587$ echo "get user@gmail.com" | nc 127.0.0.1 10099
500 NO%20RESULTThe service responds with:
- 200 followed by the URL-encoded relay server if a match is found
- 500 NO%20RESULT if no match is found
You can also check the logs for more detailed information:
$ journalctl -u postfix-mx-pattern-router -fThis project is licensed under the BSD 3-Clause License - see the LICENSE file for details.