Procmail + Postfix + Virtual Mail User Howto

This post documents my configuration of Procmail for Postfix using virtual mail users.

A virtual user is one who does not have a "real" Linux user account. Virtual mail users are extremely convenient for handling multiple mail accounts and virtual domains. This configuration allows some (privileged) virtual mail users to receive their email via procmail, and all others via postfix's standard "virtual" transport.

I use postfixadmin for virtual mailbox management, so this configuration coincides with my postfixadmin configuration. (This does not cover installation of postfixadmin on Debian.) Specifically, I use the following postfixadmin settings to define the mailbox structure:

POSTFIXADMIN CONFIGURATION
config.inc.php:
// Mailboxes
// If you want to store the mailboxes per domain set this to 'YES'.
// Example: /usr/local/virtual/domain.tld/[email protected]
$CONF['domain_path'] = 'YES';
// If you don't want to have the domain in your mailbox set this to 'NO'.
// Example: /usr/local/virtual/domain.tld/username
$CONF['domain_in_mailbox'] = 'NO';

Note that I have created a user "vmail" to handle virtual mail delivery (see postfixadmin setup):
crnatural:~# grep vmail /etc/passwd vmail:x:150:8:Virtual mailbox:/home/vmail:/sbin/nologin

On my server, this makes the path to a user mailbox to be: /home/vmail/mydomain.com/username It is important to remember that procmail must also deliver email following this path structure.

POSTFIX CONFIGURATION
First we configure procmail as an available transport type in postfix's master.cf.:

procmail unix - n n - - pipe
  -o flags=RO user=vmail argv=/usr/bin/procmail -t -m USER=${user} EXTENSION=${extension} /etc/postfix/procmailrc.common

The default transport type for virtual users will be set to be "virtual" in main.cf.

main.cf:
virtual_transport = virtual
# uncomment the following line to have procmail deliver to all virtual users
# virtual_transport = procmail
# TRANSPORT MAP
procmail_destination_recipient_limit = 1
transport_maps = hash:/etc/postfix/transport

/etc/postfix/transport:
[email protected] procmail
[email protected] procmail

With the above configuration, procmail run the procmail script at /etc/postfix/procmailrc.common for users/domains named in /etc/postfix/transport.

/etc/postfix/procmailrc.common:
MAILDIR="$HOME/mydomain.com/$USER"
DEFAULT="$MAILDIR/"
#VERBOSE=ON
#each user will set his own log file
#LOGFILE="/home/vmail/proclog-$USER"
NL="
"
WS="    "
SWITCHRC="$HOME/.procmail/$USER"

Note that $HOME contains "/home/vmail," the home directory of the user that handles virtual mail delivery.  Thus, the delivery path matches the virtual mail delivery path.

Bugs: This setup hard-codes the delivery domain, so it can only deliver to email addresses on a single domain.  To deliver to more than one domain, you could pass the full destination email address as an argument to procmail, and write procmail recipes to extract the domain for the SWITCHRC assignment.

(See comments below for code to do multiple-domain delivery in 2 different ways.)

Credits: The idea for this configuration came from a post on the procmail mailing list, procmail Digest, Vol 53, Issue 4 (procmail at lists.RWTH-Aachen dot DE) by "LuKreme"

procmail doesn't make mailbox automatically

Thank you for nice document.

I tried this tips. and I have a problem.

If there is no directory on MAILDIR(=$HOME/$DOMAIN/$USER), procmail doesn't make MAILDIR automatically.
and procmail save mail to DEFAULT(="$MAILDIR/") in this case DEFAULT=/home/vmail.
If there is directory on MAILDIR, procmail work correctoly.

If I set virtual_transport = virtual, postfix automatically makes directory.

Is there any way to avoid this problem ? I want to make mailboxes automatically.

thanks.

I don't see what your

I don't see what your problem is. You say that when you set virtual_transport = virtual, postfix makes the directory, as you want.

my case

thanks for your reply.

my setting is bellow.
------main.conf-----
virtual_transport = virtual
transport_maps = regexp:/etc/postfix/transport.procmail
procmail_destination_recipient_limit = 1
transport_destination_recipient_limit = 1
------transport.procmail----
^nama@/ procmail
----------------------------
In this case, if there is no directory on
/home/vmail/$user, mail send to DEFAULT.
But if i remove a regrex maps(/^nama@/ procmail),
directory (/home/vmail/$user) is created.

I want to make directory automatically when I use procmail with
transport_maps.

that makes sence?

thanks.

Did you make sure that you

Did you make sure that you have regex lookup in your postfix? (Run postconf -m and check for 'regexp' in the output.)

Aside from that, your regexp syntax is missing a forward slash. To match what you are trying to match, you want:
/^nama@/ procmail

For more information try http://www.postfix.org/regexp_table.5.html
--
Lloyd

I'm sorry it's typo. I

I'm sorry it's typo.

I wrote
/^nama@/ procmail
in transport.procmail

> Did you make sure that you have regex lookup in your postfix? (Run postconf -m and check for 'regexp' in the output.)
yes. postconf -m outputed 'regexp'.

Make sure the directory that

Make sure the directory that holds your mailbox files is writable by the virtual mail user. In my case it is user 'vmail', and my permissions for domain 'crnatural.net' look like this:

crnatural:/home/vmail# ls -l
total 4096
drwx------ 4 vmail mail 4096 May 19 2008 crnatural.net

I checked the permissions

I checked the permissions and it's no problem.
According to the procmail log, if there is no directory, procmail said bellow.
-----------------------------------
procmail: Assigning "LASTFOLDER=./new/.1608_1.mydomain.com"
Subject: TEST
Folder: ./new/.1505_1.mydomain.com 1144
procmail: [1608] Fri May 15 01:38:18 2009
-----------------------------------

but if there is a directory, like this
-----------------------------------
procmail: Assigning "LASTFOLDER=/var/vmail/users/nama/Maildir/new/.1757_1.mydomain.com"
Subject: TEST
Folder: /var/vmail/users/nama/Maildir/new/.1757_1.mydomain.com
procmail: [1757] Fri May 15 01:49:07 2009
-----------------------------------

"Folder:" is different. Is this procmail problem ?

I don't think it is a

I don't think it is a procmail problem, I think it is a procmail configuration problem related to file permissions. Probably you do not have virtual_minimum_uid and virtual_uid_maps set properly. If the virtual mail user ID number is 150 (look in /etc/passwd), the settings (in main.cf) would be:

virtual_minimum_uid = 150
virtual_uid_maps = static:150

I think you should get postfix working properly with virtual users before attempting to add procmail as a transport. There are plenty of good tutorials on the web on doing that (eg http://bliki.rimuhosting.com/space/knowledgebase/linux/mail/postfixadmin+on+debian+sarge).

May be, I understood that

May be, I understood that it's a procmail problem.

checked that problem following steps.

1. making a test procrc, like this.
-----------------------
MAILDIR="/home/nama/users/$USER/Maildir"
DEFAULT="$MAILDIR/"
LOGFILE="./testprocmail"
VERBOSE=YES
-----------------------

2, test procrc
--------------------
bash> procmail -m USER=nama procmailrc < sometext.file
--------------------
Then, procmail said.
--------------------
procmail: Couldn't chdir to /home/namai/users/nama/Maildir
--------------------
and sometext.file delivered to ~/new.
according to testprocmail, the same things happened which i reported before.

3. make "/home/namai/users/nama/Maildir" before procmail executing.
--------------------
bash> mkdir -p /home/namai/users/nama/Maildir
bash> procmail -m USER=nama procmailrc < sometext.file
--------------------
and sometext.file delivered to /home/namai/users/nama/Maildir

so, I think it's a procmail problem.
may be, procmail can't recursively make MAILDIR.

thanks.

I solved the bug by adding

I solved the bug by adding $NEXTHOP=${nexthop} in master.cf
procmail unix - n n - - pipe
-o flags=RO user=vmail argv=/usr/bin/procmail -t -m USER=${user} EXTENSION=${extension} NEXTHOP=${nexthop} /etc/postfix/procmailrc.common

then I changed mydomain.com in $NEXTHOP in procmailrc.common

You also can use $NEXTHOP if you have same users in different domains.
Like SWITCHRC="$HOME/.procmail/$USER-$NEXTHOP"

I don't know what $EXTENSION is doing, but it's empty in my setup.

Fixing delivery for multiple domains

That's a cool fix! Thanks very much! Did you test that for virtual domains? If your fix works perfectly, it is probably better (simpler) than my solution below.

I also had a need to fix this, and this is how I did it. I modified the procmail service line in master.cf as follows:

procmail unix - n n - - pipe
flags=DRO user=vmail argv=/usr/bin/procmail -t -m USER=${user} RECIPIENT=${recipient} /etc/postfix/procmailrc.common

I added what's in boldfaced: RECIPIENT=${recipient}. Note that I removed EXTENSION=${extension}, since I don't use it.

The "O" flag prepends an "X-Original-To: recipient" message header with the recipient address as given to Postfix. Note: for this to work, the procmail_destination_recipient_limit (in main.cf) must be 1.

Next, I modifed procmailrc.common as follows (this is my full procmailrc.common):
----------------------------------------------
:0
* RECIPIENT ?? .*@\/.*$
{ DOMAIN = "$MATCH" }
#added RECIPIENT variable and we extract domain name
MAILDIR="$HOME/$DOMAIN/$USER"
DEFAULT="$MAILDIR/"
#each user will set his own log file
NL="
"
WS=" "
SWITCHRC="$HOME/.procmail/$USER"
-------------------------------------------------

Notes: The "\/" in this recipe captures everything that matches after it to the variable MATCH. The idea, of course, is to extract the domain name from the email address.