Zimbra configuration
Zimbra runs its own Postfix as the zimbra user and regenerates main.cf from its configuration on every zmmtactl restart or zmmtactl reload.
Do not edit Zimbra's main.cf directly - the changes will be lost on the next MTA restart. Use zmprov so the milter settings persist.
Start the milter service first (see Server installation) before wiring Zimbra to it. This way mail flows through the milter as soon as the MTA restarts.
Commands
Run the following as the zimbra user on the Zimbra server:
sudo su - zimbra
zmprov ms $(zmhostname) zimbraMilterServerEnabled TRUE
zmmilterctl start
zmprov ms $(zmhostname) zimbraMtaSmtpdMilters "inet:localhost:7080"
zmprov ms $(zmhostname) zimbraMtaNonSmtpdMilters "inet:localhost:7080"
zmprov ms $(zmhostname) zimbraMtaMilterDefaultAction accept
zmmtactl reload
Description
Switch to the zimbra user. All zmprov and zmmtactl commands must run as this user.
sudo su - zimbra
Zimbra 8.6 and later have a bug that can overwrite Postfix's smtpd_milters parameter with an empty value, so the milter silently stops receiving mail (Bug 97706). Work around it by enabling Zimbra's own milter server (zimbraMilterServerEnabled) and starting it with zmmilterctl start before configuring the MSH Zimbra Rules milter below, even if you do not otherwise use Zimbra's built-in milter - see the FAQ for what that built-in milter actually does.
zmprov ms $(zmhostname) zimbraMilterServerEnabled TRUE
zmmilterctl start
Register the milter for mail arriving over SMTP (from external clients and other mail servers).
zmprov ms $(zmhostname) zimbraMtaSmtpdMilters "inet:localhost:7080"
Register the milter for locally injected mail (sendmail, cron jobs, local applications). Set it only if you also want internally generated mail filtered.
zmprov ms $(zmhostname) zimbraMtaNonSmtpdMilters "inet:localhost:7080"
Set the default action Postfix takes when the milter is unavailable. With accept, mail still flows if the milter is down instead of being deferred. Use tempfail instead if you would rather hold mail when the milter is unavailable.
zmprov ms $(zmhostname) zimbraMtaMilterDefaultAction accept
Reload the Zimbra MTA so Postfix regenerates its configuration with the milter settings.
zmmtactl reload
Verify
Confirm Postfix picked up the milter after the reload (still as the zimbra user):
postconf smtpd_milters non_smtpd_milters milter_default_action
Expected output:
smtpd_milters = inet:localhost:7080
non_smtpd_milters = inet:localhost:7080
milter_default_action = accept
Caveats
Zimbra's own milter is also used for distribution-list access control
zimbraMilterServerEnabled is enabled above purely as the Bug 97706 workaround (see the FAQ for what it actually does). If you also actually use Zimbra's built-in milter for distribution-list access control, it populates smtpd_milters with its own socket too. In that case set zimbraMtaSmtpdMilters to a value that includes both sockets, so you do not drop Zimbra's milter:
zmprov ms $(zmhostname) zimbraMtaSmtpdMilters "inet:localhost:7026 inet:localhost:7080"
Check the current value with zmprov gs $(zmhostname) zimbraMtaSmtpdMilters before overwriting it.
Older Zimbra versions
Older Zimbra versions may not expose the zimbraMtaSmtpdMilters / zimbraMtaNonSmtpdMilters / zimbraMtaMilterDefaultAction server attributes. Use zmlocalconfig instead:
zmlocalconfig -e postfix_smtpd_milters=inet:localhost:7080
zmlocalconfig -e postfix_non_smtpd_milters=inet:localhost:7080
zmlocalconfig -e postfix_milter_default_action=accept
Either mechanism works; verify what your version uses and avoid configuring the same milter twice.
What's next
- Connect to the web admin UI - log in and create your first rules
- Troubleshooting Zimbra configuration - verify the milter is applied and test the mail flow