← Documentation Index


Mailmunge should run on any reasonably-modern UNIX or Linux system. This document explains how to install Mailmunge from source and configure it.


To use Mailmunge, you need the following:

On a Debian Linux system, you can install all the prerequisites with:

  apt install libmime-tools-perl libperl-dev perl perl-modules      \
              libio-socket-ssl-perl spamassassin                    \
              libfile-find-rule-perl libtest-deep-perl cpanminus    \
              build-essential libjson-any-perl libmilter-dev        \
              clamav-base clamav-daemon clamav-freshclam            \

  cpanm -n File::VirusScan

  # Only if you plan on using Postfix...
  apt install postfix

  # Only if you plan on using Sendmail...
  apt install sendmail sendmail-bin sendmail-cf

The recipe for Rocky Linux 8 and probably other Red Hat 8 derivatives is:

  dnf -y group install --setopt group_package_types=mandatory "Development Tools"
  dnf -y install epel-release
  dnf config-manager --set-enabled powertools

  dnf -y install perl-MIME-tools perl-Sys-Syslog sendmail-milter     \
     perl-ExtUtils-MakeMaker sendmail-milter-devel perl-Test         \
     perl-Test-Simple perl-Test-Deep perl-HTML-Parser perl-Net-DNS   \
     perl-File-Find-Rule spamassassin perl-JSON-Any perl-DBD-SQLite  \
     perl-Test-Pod perl-Test-Pod-Coverage clamav clamav-data clamd   \

  cpanm -n File::VirusScan

  # If you plan on using postfix
  dnf -y install postfix

  # If you plan on using Sendmail
  dnf -y install sendmail sendmail-cf


Mailmunge uses the standard UNIX build invocation:

   tar xfz mailmunge-VERSION.tar.gz
   cd mailmunge-VERSION
   make install    # This one has to be run as root (eg, with "sudo")

Run ./configure --help to see the available configuration options. The make install target supports the standard DESTDIR=/path variable to let you install under a separate directory hierarchy; this is of most interest to people interested in packaging Mailmunge.


You can run Mailmunge's unit tests as follows; the command assumes you're currently in the top-level Mailmunge source directory.

  make test

For more verbose output:

  make test TEST_VERBOSE=-v

Don't run the unit tests as root; they will fail.


Mailmunge ships with four Docker files for creating containers that do regression tests. The four files are for the four combinations of (Sendmail, Postfix) as the MTA, and (Debian 10, Rocky Linux 8) as the Linux distribution.

To run the Docker regression tests, you must (obviously) have Docker installed and your user-ID must have permission to create and run docker images and containers.

To create a Docker container for running regression tests:

  # If you want to run tests with Postfix on Debian 10:
  cd docker; ./build-docker-container postfix debian

  # If you want to run tests with Sendmail on Debian 10:
  cd docker; ./build-docker-container sendmail debian

  # If you want to run tests with Postfix on Rocky Linux 8:
  cd docker; ./build-docker-container postfix rocky

  # If you want to run tests with Sendmail on Rocky Linux 8:
  cd docker; ./build-docker-container sendmail rocky

It can take quite a while (around 30 minutes) to create each container image.

To run the regression tests:

  # If you want to run tests with Postfix on Debian 10:
  cd docker; ./run-regression-tests-on-docker postfix debian

  # If you want to run tests with Sendmail on Debian 10:
  cd docker; ./run-regression-tests-on-docker sendmail debian

  # If you want to run tests with Postfix on Rocky Linux 8:
  cd docker; ./run-regression-tests-on-docker postfix rocky

  # If you want to run tests with Sendmail on Rocky Linux 8:
  cd docker; ./run-regression-tests-on-docker sendmail rocky

If a Mailmunge source tree already exists in the container, run-regression-tests-on-docker won't rebuild it by default. To force a rebuild, add -f to the end of one of the above command-lines.

In addition to -f, you can use -v for more verbose test output and -c for colored test output.



Postfix often runs in a chroot environment, which makes using a UNIX-domain socket to communicate with mailmunge challenging. Instead, use a TCP socket. In the examples below, we're assuming you chose TCP port 8872 for Milter communication, but you can choose any available unprivileged port.

Edit your Postfix main.cf file to include the following lines:

  smtpd_milters = inet:
  non_smtpd_milters = inet:
  milter_default_action = tempfail

Again, the above lines assume that mailmunge has been configured to listen on the appropriate socket. In this case, the option would be -p inet:8872@


To configure Sendmail to use Mailmunge, edit the sendmail.mc file and add a line like this:

  INPUT_MAIL_FILTER(`mailmunge', `S=unix:/var/spool/mailmunge/mailmunge.sock, F=T, T=S:360s;R:360s;E:15m')dnl

and regenerate your sendmail.cf file. The "T=S..." sets various timeouts for the Milter code; consult Sendmail's reference manual for details.

The above line assumes that mailmunge is listening on the socket /var/spool/mailmunge/mailmunge.sock; you should use the corresponding option -p /var/spool/mailmunge/mailmunge.sock when invoking mailmunge.


The spool directory (typically /var/spool/mailmunge) is performance-critical and does not hold any persistent data. As such, it can (and should) be mounted on a RAM disk. On Linux, you can put this in /etc/fstab to put /var/spool/mailmunge on a RAM disk:

 tmpfs /var/spool/mailmunge tmpfs nosuid,nodev,uid=mailmunge,gid=mailmunge,mode=0750

Note that the uid= and gid= parameters assume that you are running Mailmunge as the user mailmunge (which is the default.) Adjust as appropriate if you run Mailmunge as some other user.


Mailmunge ships with both a SYSV-init style init script in sysvinit/mailmunge and systemd units in systemd-units/mailmunge.service and systemd-units/mailmunge-multiplexor.service

Both the sysvinit script and the systemd units read a file called /etc/default/mailmunge for environment variable settings. The following tables show how the environemt variable settings map to mailmunge and mailmunge-multiplexor options.

In the tables below, add the setting in the right-hand column to /etc/default/mailmunge to enable the option in the left-hand column. The word "yes" is literal; other words like "num" or "facility" depend on the specific option they affect.

The sysvinit script

Assuming you have installed the sysvinit/mailmunge script in /etc/init.d/, use the following to control Mailmunge:

  /etc/init.d/mailmunge start    # Start mailmunge and mailmunge multiplexor
  /etc/init.d/mailmunge stop     # Stop mailmunge and mailmunge multiplexor
  /etc/init.d/mailmunge restart  # Stop and then start mailmunge and mailmunge multiplexor
  /etc/init.d/mailmunge status   # Show status of mailmunge and mailmunge-multiplexor
  /etc/init.d/mailmunge reload   # Tell mailmunge-multiplexor to reload filter rules
  /etc/init.d/mailmunge reread   # Synonym for reload

The systemd units

Note that you should only invoke the mailmunge unit; it takes care of also invoking mailmunge-multiplexor for you.

  systemctl start mailmunge   # Start mailmunge and mailmunge multiplexor
  systemctl stop mailmunge    # Start mailmunge and mailmunge multiplexor
  systemctl restart mailmunge # Stop and then start mailmunge and mailmunge multiplexor
  systemctl reload mailmunge  # Tell mailmunge-multiplexor to reload filter rules
  systemctl status mailmunge  # Show status of mailmunge service

Variables that affect mailmunge options:

 mailmunge option           /etc/default/mailmunge setting

  -C                        MM_CONSERVE_DESCRIPTORS=yes
  -G                        MM_ALLOW_GROUP_ACCESS=yes
  -H                        MX_HELO_CHECK=yes
  -N                        MM_SUPPRESS_REJECTED_RCPTS=yes
  -P pidfile                MM_PIDFILE=pidfile
  -R num                    MM_RESERVED_FOR_LOOPBACK=num
  -S facility               SYSLOG_FACILITY=facility
  -T                        LOG_FILTER_TIME=yes
  -U username               MX_USER=username
  -X                        SUPPRESS_SCANNED_BY=yes
  -b backlog                MM_LISTEN_BACKLOG=backlog
  -c                        STRIP_BARE_CR=yes
  -k                        KEEP_FAILED_DIRECTORIES=yes
  -m mx_socket              MX_SOCKET=mx_socket (UNIX socket path)
  -p socket                 SOCKET=socket (UNIX socket path or inet:port)
  -q                        ALLOW_CONNECTIONS_TO_QUEUE=yes
  -r                        MX_RELAY_CHECK=yes
  -s                        MX_SENDER_CHECK=yes
  -t                        MX_RECIPIENT_CHECK=yes
  -x string                 SCANNED_BY=string
  -y                        USE_SMFI_SETSYMLIST=yes
  -z spooldir               SPOOLDIR=spooldir
  (extra options)           MM_EXTRA="-a foo -a bar"  # Any extra options

Variables that affect mailmunge-multiplexor options:

 mailmunge-multiplexor      /etc/default/mailmunge setting
  -E                        MX_EMBED_PERL=yes
  -G                        MM_ALLOW_GROUP_ACCESS=yes
  -I backlog                MX_LISTEN_BACKLOG=backlog
  -L secs                   MX_LOG_WORKER_STATUS_INTERVAL=secs
  -M limit                  MX_MAX_AS=limit
  -N socket                 MX_MAP_SOCKET=socket
  -O notify_socket          MX_NOTIFIER=notify_socket
  -P num                    MX_PARALLEL_TICKS=num
  -Q timeout                MX_QUEUE_TIMEOUT=timeout
  -R limit                  MX_MAX_RSS=limit
  -S facility               SYSLOG_FACILITY=facility
  -T                        MX_STATS_SYSLOG=yes
  -U username               MX_USER=username
  -V lifetime               MX_MAX_LIFETIME=lifetime
  -W secs                   MX_MIN_WORKER_DELAY=secs
  -X secs                   MX_TICK_INTERVAL=secs
  -Y label                  MX_SYSLOG_LABEL=label
  -Z                        MX_STATUS_UPDATES=yes
  -a socket                 MX_UNPRIV_SOCKET=socket
  -b timeout                MX_BUSY=timeout
  -c timeout                MX_CMD_TIMEOUT=timeout
  -f path_to_filter         FILTER=path_to_filter
  -i timeout                MX_IDLE=timeout
  -l                        MX_LOG=yes
  -m num                    MX_MINIMUM=num
  -p pidfile                MX_PIDFILE=pidfile
  -q size                   MX_QUEUE_SIZE=size
  -r num                    MX_REQUESTS=num
  -s socket                 MX_SOCKET=socket
  -w secs                   MX_WORKER_DELAY=secs
  -x num                    MX_MAXIMUM=num
  -y num                    MX_RECIPOK_PERDOMAIN=num
  -z path_to_spooldir       SPOOLDIR=path_to_spooldir


The init scripts use the following defaults for environment variable settings (which may be overridden in /etc/default/mailmunge

  MX_USER=mailmunge                              # Or whatever ./configure picked
  MX_GROUP=mailmunge                             # Or whatever ./configure picked
  SPOOLDIR=/var/spool/mailmunge                  # Or whatever ./configure picked
  MX_PIDFILE=/var/run/mailmunge-multiplexor.pid  # sysvinit script only
  MM_PIDFILE=/var/run/mailmunge.pid              # sysvinit script only

Note that the systemd units do not make use of pidfiles by default, but you can force them to be created by setting MX_PIDFILE and MM_PIDFILE in /etc/default/mailmunge

Copyright © 2021 Skoll Software Consulting