As mentioned in the MAQ, this is needed if you need to apply different rules depending on the individual recipient in a multi-recipient message.
Postfix is very well able to do this, by use of the default_destination_recipient_limit = 1 setting, but unfortunately ... this will split the mails after MailScanner has done its thing. Not good. This behaviour has led a lot of people to believe that you cannot do this type of thing with Postfix1)... But they are wrong
.
The actually quite simple solution is to have two separate instances of Postfix, one that receives mail on port 25, does the split, then passes everything on to the second instance, that does the normal HOLD thing, and delivers the mails onward after MailScanner is done.
To facilitate this we need use the transport_map override feature, so we cannot just fiddle with a single instance of Postfix and its master.cf settings, but actually need the two instance setup. We need different settings in at least the transport map, main.cf, master.cf and header_checks.
The steps are a bit reminiscent of the deprecated and unsafe “two instance defer” method we used to use a couple of years back, with the glaring exception that this setup will be completely safe to use since we will only be using an SMTP interface between the two instances (in keeping with the recommendations of the postfix developers, this is a “supported interface”
) and MailScanner will not come into play until the second instace puts the messages into the hold queue. Here goes...
These examples are from a Mandriva setup close by me, which would be pretty much the same on most any system (especially RedHat descendants
). SuSE, Debian-ish, Solaris and *BSD systems might differ slightly in paths etc.
service MailScanner stopcp -a /etc/postfix /etc/postfix.in cp -a /var/spool/postfix /var/spool/postfix.in
/etc/postfix.in/transport so that it only contains (apart from comments) a line: * smtp:[127.0.0.1]:10026
/etc/postfix.in/master.cf and see to it that it does not contain any smtpd apart from the default one: ... smtp inet n - y - - smtpd ... #127.0.0.1:10026 inet n - y - - smtpd # -o content_filter= ...
/etc/postfix.in/header_checks and see to it that it does not contain the HOLD line (but it should contain all other header checks you wish to employ):... # This is needed for the one instance postfix implementation of MailScanner. -- Glenn #/^Received:/ HOLD
/etc/postfix.in/main.cf and see to it that it contains:... queue_directory = /var/spool/postfix.in transport_maps = hash:/etc/postfix/transport.in default_destination_recipient_limit = 1 ...
This will force the delivery of all emails to the second instance, and thus the split into one message per recipient.
postmap the transport table with: postmap -c /etc/postfix.in hash:/etc/postfix.in/transport
/etc/postfix/header_checks and make sure it contains the HOLD thing:# This is needed for the one instance postfix implementation of MailScanner. -- Glenn
/^Received:/ HOLD/etc/postfix/master.cf and see to it that it does not contain the default smtpd, but rather one listening only to localhost port 10026: ... #smtp inet n - y - - smtpd ... 127.0.0.1:10026 inet n - y - - smtpd -o content_filter= -o smtpd_restriction_classes= -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o smtpd_authorized_xforward_hosts=127.0.0.0/8 -o strict_rfc821_envelopes=yes -o receive_override_options=no_unknown_recipient_checks -o header_checks=regexp:/etc/postfix/header_checks_hold -o transport_maps= -o smtpd_client_connection_limit_exceptions=127.0.0.0/8 ...
I “borrowed” this from the default “AFTER filter” setup on my machine, but you could as well have set all those settings in /etc/postfix/main.cf ... I was just a tad lazy here
. In fact, I do set the “transport_maps = ” explicitly, mostly because I had forgotten about the changes in master.cf
. Note: If you need a transport map, look at point 12 below.
/etc/postfix/main.cf and explicitly set:... transport_maps = ...
Note: If you need a transport map, look at point 12 below.
syslog_facility and syslog_name settings)/etc/postfix/master.cf you need:# An smtpd to handle releasing from quarantine... By bypassing MS entirely 127.0.0.1:10027 inet n - y - - smtpd -o content_filter= -o smtpd_restriction_classes= -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o smtpd_authorized_xforward_hosts=127.0.0.0/8 -o strict_rfc821_envelopes=yes -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks -o smtpd_client_connection_limit_exceptions=127.0.0.0/8
which is very similar to the one needed for MailScanner, but with the important difference that it’ll actually deliver the mails since it skips the header checks (and hence the HOLD thing). A tool that will work with this as a “sendmail replacement” is Jef Poskanzers mini_sendmail, so get that and install it (you could very easily type up your own using Perl and Net::SMTP, but why bother?:). You use this a bit like the sendmail command, but it’ll talk SMTP and you can tell it to use non-standard ports, like
mini_sendmail -p10027 -t -i < /path/to/message
or
mini_sendmail -p10027 -t -i < /path/to/message
If you use MailWatch with the oldstyle Pear Mail functions you don’t really need mini_sendmail, just change functions.php from (this is for version 1.0.3)
$mail_param = array('host' => QUARANTINE_MAIL_HOST, 'localhost' => QUARANTINE_MAIL_HELO);
to
$mail_param = array('host' => QUARANTINE_MAIL_HOST, 'localhost' => QUARANTINE_MAIL_HELO, 'port' => 10027);
.... and that would be “it”
.
If you use the new define(QUARANTINE_USE_SENDMAIL, true);, then you need use mini_sendmail, so set define(QUARANTINE_SENDMAIL_PATH, ‘/usr/sbin/mini_sendmail’); and then change functions.php from
$cmd = QUARANTINE_SENDMAIL_PATH." -i -f ".QUARANTINE_FROM_ADDR." $to < ";
to
$cmd = QUARANTINE_SENDMAIL_PATH." -i -p10027 ".QUARANTINE_FROM_ADDR." $to < ";
... and you should be done. Again, if you don’t need this type of workaround, then don’t use it... Test first to release by your normal measures ... If they don’t work, then ... configure away