Command-Based Filtering
The simplest way to set up content filtering is to use a program that runs as a command and accepts the contents of a message on its standard input. Postfix delivers messages to your filter command via the pipe mailer. Your filter command performs its checking and then gives the filtered message back to Postfix using the Postfix sendmail command.
For this discussion, we'll assume that the filter command operates on mail that comes in through the SMTP daemon but not on mail that is delivered locally (using the sendmail command), so that your filter can use sendmail to give the message back to Postfix without looping. Figure 14-1 illustrates the path messages follow once you put your filter in place. Rather than passing the message to a delivery agent, the queue manager invokes the filter.
Figure 14-1. Mail-filtering command
Your filter program must be able to accept the message on its standard input and then deliver it to the Postfix sendmail command. If you have a filtering program that doesn't handle input and output in this way it should be easy enough to create a shell script wrapper to deal with those details. In the Postfix distribution, the FILTER_README file contains an example of such a script.
14.1.1 Configuration
When you configure Postfix to use your filter program, you must specify a user that the program runs as. You should create a pseudoaccount whose sole purpose is to run the filter.
Let's set up an example configuration and assume that you have a filter program named simple_filt stored at /usr/local/bin and that you have created a pseudouser called filter to run it. Edit your master.cf file to add an entry for your filter:
filter unix - n n - - pipe flags=Rq user=filter argv=/usr/local/bin/simple_filt -f ${sender} -- ${recipient}
The first line contains all of the standard settings for a Postfix component entry with the last column indicating that the message should be handled by the Postfix pipe daemon. The second and third lines are a continuation of the first because of the whitespace at the beginning. They contain options the pipe service will use when executing the command. The options R and q, specified as flags, tell the pipe service to prepend a Return-Path: header and to quote whitespace and special characters in the ${sender} and ${recipient} addresses that are passed to the command. See the pipe(8) man page for other possible options.
The user= option is the filter pseudouser that you set up for running your filter command. The argv option specifies the actual command along with its arguments to execute. The argument list specified here (-f ${sender} -- ${recipient}) can be used exactly as is by the script when it invokes the sendmail command to deliver the message back to Postfix. Your own filter may require different arguments, but make sure you include the items you need to send the message back to Postfix through the sendmail command. The ${recipient} variable is expanded by the pipe daemon into multiple recipients up to the limit specified in the filter_destination_recipient_limit parameter when a message has more than one recipient.
In addition to the new component entry, you must also make a change to the smtpd entry in master.cf to turn on filtering for all messages that are delivered to the SMTP daemon:
smtp inet n - n - - smtpd -o content_filter=filter:
Simply add the second line in the preceding example to your existing smtpd line. Don't forget the initial whitespace to indicate that it is a continuation of the previous line. The content_filter parameter is set equal to the entry you just created in master.cf for your filter program. Set this option here rather than in main.cf because it should apply to the smtpd daemon only and not for every message that enters the Postfix system. After you reload Postfix, all messages coming in over SMTP will now be handled by your filter program.
A filter of this sort, although easy to configure, is not the most efficient method of filtering. It requires that Postfix invoke a shell or interpreter and that the filter invoke sendmail to resubmit the filtered message. If your program runs into problemsdisk space or memoryfor example, there isn't a reliable way for it to report the exact problem back to Postfix. Daemon-based filtering described in the next section offers a more robust solution with better performance.[1]
[1] All else being equal. The performance depends largely on the content-filtering program itself.