VDA Autoresponders
The Postfix Virtual Delivery Agent ( VDA, aka virtual(8) ) is a local delivery
agent written to abstract the email user from the system user. virtual(8) is a
ment to handle the task of getting messages from the queue manager (qmgr) into a
local mailbox. What makes virtual(8) different than local(8) is that the location
of the mailbox is determined witha map lookup. The UID/GID owning the mailbox
is also configured with a map. This allows the postmaster to place the mailboxes
anywhere on disk they like. When combined with a modern POP3/IMAP server this can
be a fantastic way to manage mailboxes.
The design of virtual(8) limits its usefulness in some cases. While local(8) can
execute commands from an aliases or .forward file, virtual(8) will not do either.
Since virtual(8) is run as a configurable (on a per mailbox basis) UID, it does
not even attmept to enter security sensative realms such as program execution.
But almost every "vacation" program out there is run from a .forward file, which
implies real system users. The solution is to use other parts of postfix to get
around the (good) limitations of virtual(8).
This is where the names of some of the postfix processes gets in the way. Postfix
has two components named "virtual". There is virtual(5) and there is virtual(8).
The VDA is virtual(8), where the (8) simply refers to the section of the manpages
where this process's documentation is. The other "virtual", virtual(5) is really a
map format used by the cleanup(8) daemon to rewrite the recipient address of emails
as they come in. The naming is confusing but the purpose of each is clearly seperate.
In the quest of a working autoresponder virtual(5) is going to help us split each
incoming email into two. One will be allowed to pass to the VDA and another will be
sent to a different, specially formatted address.
"What specially formatted address?" you say. Well, this is the tricky bit. We need to
get the email message to an autoresponder program. That autoresponder will be explained
in a moment. The most secure way to do this is through Postfix's pipe(8) transport. We
can have pipe(8) run our autoresponder program and we can get message to pipe using a
transport map. I told you this was tricky. Here is a little diagram of how this will work.

Message 1 comes in via STMP and gets split during cleanup into messages 2 and 3. Both
are given to the queue manager which sends the message with the original recipient
address off to virtual(8) for placement in the user's maildir. Message 3 is routed
via a transport map to the pipe transport set to run our autoreply command. The
autoreply command looks at the message and forms a new message if it decides it should
reply to the message. This final message, number 4, leave postfix via SMTP (some
steps are ommitted for the path of message 4, but you get the idea).
Most versions of postfix can route mail in a transport map based on the recipient's domain
name (very new snapshots can do this on a per-address basis). Assuming the server is handling
the email for example.com (please don't try to use this, I'm sure the postmaster@example.com
has better things to do), we will create a subdomain called autoreply.example.com. Now this
subdomain does not have to exist in DNS, in fact it may be better that it doesn't. It only
exists in our transport map and our virtual(5) rewrite table. Your transport map (normally
located at /etc/postfix/transport) should look like this:
example.com virtual:
autoreply.example.com autoreply:
Make sure to run postmap /etc/postfix/transport after editing this file. At this point
if you email something @autoreply.example.com it will fail since we haven't defained what the
autoreply transport is. Carefully add the following lines to /etc/postfix/master.cf :
autoreply unix - n n - - pipe
flags=F user=nobody
argv=/usr/bin/perl /usr/local/bin/autoreply.pl $sender $recipient
autoreply.pl is a perl script that uses Net::LDAP to pull the autoresponder message out of a
directory server. This script is not currently available. I hope to release the source code as
soon as it clears my employer's legal department. Watch this space. I will provide the disign of
such a beast in another document. Here are the basics of the program. It takes the original envelope
sender and the specially formatted envelop recipient on the command line. It then parses out
the original envelope recipient and checks to see that an autoresponder message exists for this
address. If one does then it checks a local database to see if it has already replied to this
sender/recipient pair in the last 24 hours. It checks the sender against a list of known "don't reply"
addresses (MAILER-DAEMON@, postmaster@, *-owner@). If all these checks pass it formats and sends a
new message, copying the original subject.
As for the "specially formatted" recipient addresses, we need to take the original address and somehow
change it to be @autoreply.example.com, but still contain an encoded version of the original address.
I chose a very simple way of doing this. I took the original recipient address and replaced the '@'
with a '#', and appended the resulting string to @autoreply.example.com. So if the address in question
was john@exmaple.com, the new recipient address would be john#example.com@autoreply.example.com. I do
this because my autoresponder can handle any number of domains. If you only have one domain, your address
encoding might be as simple as john@autoreply.example.com. This way to enable or disable the
autoresponder for a given user, you just add or remove the specially formatted entry from the virtual
table. Here is an example of what that virtual map might look like:
john@exmaple.com john@example.com,john#example.com@autoreply.example.com
Since we're using both a transport map and a virtual(5) map, be sure you have the following entries in
your main.cf file:
virtual_maps = hash:/etc/postfix/virtual
transport_maps = hash:/etc/postfix/transport
That concludes this document. If you have questions feel free to post them to the postfix-users mailling list.
Back to Pavo's Postfix Page
|