Postfix Scripting – How to Pipe All Incoming Email to a Script

postfixscripting

Using postfix, I'd like all incoming mail, to any address (including those that don't map to local users) to be piped to a script. I've tried configuring mailbox_command in /etc/postfix/main.cf:

mailbox_command = /path/to/myscript.py

This works great if the user is a local user, but it fails for "unknown" users who don't have aliases. I tried setting luser_relay to a local user, but this pre-empts mailbox_command, and so the command doesn't get run. I tried setting local_recipient_maps= (empty string), but the message is still bounced (unknown user).

Is there a magic invocation I can use to get all known and unknown users to go to the script as well?

Full /etc/postfix/main.cf follows — it's the default Ubuntu 10.04, with the exception of the mailbox_command line:

# See /usr/share/postfix/main.cf.dist for a commented, more complete version


# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

myhostname = ... snip ...
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = sassafras, ... snip ...,localhost.localdomain, localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

mailbox_command = /path/to/my/script.py

Best Answer

Ok, I just got this working -- though hairier than I thought it would be. I dropped the maildir_command part, and went with transport_maps. The key is to do 5 things:

  1. Set up a db file to handle aliases (and add a catch-all alias)
  2. Set up a db file to map the 'transport' for the domain in question to a special handler.
  3. Compile the db files into berkeley db format that postfix wants.
  4. Set up the handler in /etc/postfix/master.cf to pipe mail to the script.
  5. Set /etc/postfix/main.cf to use the transport db for transport_maps, and the alias db for virtual_alias-maps.

(1) Create /etc/postfix/virtual_aliases to add a catch-all alias -- localuser needs to be an existing local user:

@mydomain.tld   localuser@mydomain.tld

(2) Create /etc/postfix/transport to add a transport mapping. "mytransportname" can be whatever you want; it's used below in master.cf:

mydomain.tld    mytransportname:

(3) Next, both transport and virtual_aliases need to be compiled into berkeley db files:

$ sudo postmap /etc/postfix/virtual_aliases
$ sudo postmap /etc/postfix/transport

(4) Add the transport to /etc/postfix/master.cf:

mytransportname   unix  -       n       n       -       -       pipe
  flags=FR user=localuser argv=/path/to/my/script.py
  ${nexthop} ${user}

(5) In /etc/postfix/main.cf:

  ...
  transport_maps = hash:/etc/postfix/transport
  virtual_alias_maps = hash:/etc/postfix/virtual_aliases

And... good to go! Sheesh.

Related Topic