Each message to a local user must go to an address that is obtained by running an external command. That command will look at the local address tag, make API calls to several processes, and then calculate the destination address.

For example, we could use a .forward file in the user's home directory to pipe the message to the command (|command), which would then be responsible for forwarding the message, too. "An alias or ~/.forward file may list any combination of external commands, destination file names, :include: directives, or mail addresses." See: www.postfix.org/local.8.html Also: www.postfix.org/aliases.5.html

Maybe it need only adjust the To header and re-send the message via Postfix? Something tells me it's not so simple. The simplest would be if Postfix itself handled the entire forwarding job, like it does when the destination address is written directly into the .forward file. But the address is unknown; it can only be determined by the command. This is the problem.

Further, if the destination address cannot be determined, then the message must bounce with a failure notice supplied by the command.

Solution as implemented

This solution expands on Danila's answer. Specifically it redirects mail for certain wiki users known as "pipes" [2], relaying it instead to "minders" who are assigned in the wiki [1]. But generally it should be applicable to any relay where the destination address is dynamically determined by a script.

(a) In file /etc/postfix/main.cf:

transport_maps = regexp:/etc/postfix/transport.regexp
# enable transport mapping based on regular expressions

minder_destination_recipient_limit = 1
# See SINGLE-RECIPIENT DELIVERY [3].  relay-to-minder (master.cf) can handle only a
# single recipient per delivery, and flags DO have the same limitation.

(b) In file /etc/postfix/transport.regexp [4], do the transport mapping:

if /^pipe\+.+@zelea\.com$/
# relay all deliveries for pipe users [2] ...
!/^pipe\+bounceSpam@/ minder:
# ... except 'bounceSpam' deliveries, via master.cf 'minder' service

(c) In file /etc/postfix/master.cf, define the 'minder' service:

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
minder    unix  -       n       n       -       1       pipe
  flags=DO user=pipe argv=/usr/local/libexec/relay-to-minder ${sender} ${recipient}
# With maxproc 1 because it's sufficient, let Postfix do all queuing.
# Both flags D and O (adding headers Delivered-To and X-Original-To) require main.cf
# minder_destination_recipient_limit=1 [3]

(d) Make the relay-to-minder script executable by the user (pipe) specified in master.cf user=. The content of the script (including the latest version of these configuration notes) is located at http://zelea.com/system/host/havoc/usr/local/libexec/relay-to-minder

The script re-addresses the destination headers (still not sure that's proper), re-addresses the envelope, and feeds it back to the MTA for final delivery.


[1] zelea.com/w/Property:Minder

[2] zelea.com/w/Category:Pipe

[3] This meaning of "pipe" differs from [2]. www.postfix.org/pipe.8.html

[4] www.postfix.org/transport.5.html | www.postfix.org/regexp_table.5.html

Pardon the munged links. I haven't earned enough brownie points.

  • "The script re-addresses the destination headers (still not sure that's proper), re-addresses the envelope. " Well as long as it is okay with your MTA, it would not work with for example SES AWS as the MTA relay as they are very strict on headers readdressing, apparently for sane reasons to fight spam. But in general it is fine, no biggie. – Danila Ladner May 16 '13 at 2:43

The right way to do it is create a new transport in master.cf

Something like this:

myscript unix -  n  n   -  40   pipe
flags=R user=vmail argv=/path/to/myscript -o SENDER=${sender} -m USER=${user} EXTENSION=${extension}

You can use your own parameters.

Then you can use regexp for your catch rules

transport_maps = regexp:/etc/postfix/redirect_or_forward.regexp

Then in /etc/postfix/redirect_or_forward.regexp

Something like:

 /^user-.*@mydomain\.com/   myscript:

Read on postfix docs, there should be more extensive explanation on this. Hope this helps.

  • postfix.org/transport.5.html Thank you. This looks more flexible than the local .forward pipes, because it gives better control over how the command is invoked. But I'm still wondering how that command (myscript in your example) should go about forwarding the message. Should it just rewrite the To header and resend as usual via Postfix? Or is there something more involved? What's the best practice for actually forwarding the message? – Michael Allan May 7 '13 at 17:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.