Filtering Outbound Mail with procmail

You want to configure sendmail to filter mail addressed to specific domains using procmail as the mail filtering software

Build a mailertable that routes mail bound for specific domains through the procmail mailer.

Create a file in the /etc/procmailrcs directory that defines the specific filtering needed. Multiple filters can be used.

Create a sendmail configuration that enables the mailertable feature and adds procmail to the list of available mailers. Here are the lines that should be added to the sendmail configuration:

dnl Enable support for the mailertable

FEATURE(`mailertable')

dnl Add procmail to the list of available mailers

MAILER(procmail)

Build the sendmail.cf file, copy it to /etc/mail/sendmail.cf

The MAILER(procmail) macro adds the procmail mailer definition to the sendmail.cf file. The procmail mailer is not related to the local_procmail feature. A system can use the procmail mailer without using procmail as a local mailer, and procmail can be used as a local mailer without adding the MAILER(procmail) macro to the configuration.

The MAILER(procmail) macro does not add any code to the configuration to use the procmail mailer. You must either add custom sendmail.cf rules to reference the mailer, or route mail through the procmail mailer using the mailertable. Using the mailertable is the easiest and the recommended way to access the mailer. Here we add mailertable entries that invoke procmail:

# cd /etc/mail 

# cat >> mailertable 

example.com       procmail:/etc/procmailrcs/spam-filter

wrotethebook.net  procmail:/etc/procmailrcs/spam-filter

fake.ora.com      procmail:/etc/procmailrcs/uce-filter  

Ctrl-D 

# makemap hash mailertable < mailertable 

The example adds three entries to the mailertable that route mail through the procmail mailer. The first field in a mailertable entry is the key against which the recipient address is matched. The second field is the mailer value and the host value that sendmail uses to build the mail delivery triple. In this example, mail with a matching recipient address is routed through the procmail mailer. A few tests of a system running show this:

# sendmail -bv crooks@example.com

crooks@example.com... deliverable: mailer procmail, host /etc/procmailrcs/

spam-filter, user crooks@example.com

# sendmail -bv spammers@wrotethebook.net

spammers@wrotethebook.net... deliverable: mailer procmail, host /etc/procmailrcs/

spam-filter, user spammers@wrotethebook.net

# sendmail -bv thieves@fake.ora.com  thieves@fake.ora.com... deliverable: mailer procmail,

 host /etc/procmailrcs/  uce-filter, user thieves@fake.ora.com

When mail is routed to the procmail mailer, the host value ($h) must contain the pathname of the rc-file that procmail should use to filter the mail. In the example above, two different filters, spam-filter and uce-filter, are passed to procmail depending on the destination of the email. sendmail calls procmail from the procmail mailer using the following command:

procmail -Y -m $h $f $u

The -Y flag tells procmail to use the Berkeley Unix mailbox format. The -m flag runs procmail as a general-purpose mail filter. The first argument that follows the -m flag must be the path of the rc-file that contains the procmail filter. sendmail assigns the host value returned by the mailertable lookup to the $h macro, which it then passes to procmail as the first argument after the -m flag. Therefore, the host field of a mailertable entry that uses the procmail mailer must contain the full pathname of an rc-file.

The next two arguments passed to procmail are the envelope sender email address ($f) and the envelope recipient email address ($u). These values are available inside the procmail rc-file as variables $1 and $2, respectively.

One common technique for avoiding a loop is to add the pseudodomain .PROCMAIL to the recipient address when mail is resent to the original recipient. The pseudodomain ensures that the recipient address no longer matches a value in the mailertable, which breaks the loop. The pseudodomain is added by procmail commands in the rc-file. However, a properly configured rc-file is not the complete solution. .PROCMAIL is not a real domain, so code must be added to the sendmail.cf file to ensure that the pseudodomain is properly handled. The following m4 macros and sendmail.cf code, added to the end of the this recipe’s master configuration file, handle the .PROCMAIL pseudodomain, if one is added by the rc-file:

LOCAL_CONFIG

# Add .PROCMAIL to the pseudo-domain list

CP.PROCMAIL

LOCAL_RULE_0

# Strip .PROCMAIL and send via esmtp

R$+ < @ $+ .PROCMAIL . >        $#esmtp $@ $2 $: $1<@$2>

The LOCAL_CONFIG macro marks the start of code that is to be added to the local information section of the sendmail.cf file. In this example, we add a comment and a C command to the local information section. The C command adds .PROCMAIL to class P. Class P lists pseudodomains that sendmail should not attempt to lookup in the DNS. Adding .PROCMAIL to class P avoids the delays and wasted resources that occur when sendmail looks up a domain name that does not exist.

The LOCAL_RULE_0 macro marks the start of sendmail.cf code that is added to ruleset 0—more commonly called the parse ruleset. Specifically, the code that follows the LOCAL_RULE_0 macro is added to the ParseLocal ruleset, which is a hook into the parse ruleset where locally defined rules are addedThe parse ruleset rewrites the delivery address to a mail delivery triple.

The code that follows the LOCAL_RULE_0 macro in the example is a comment and a rewrite rule. The R command matches input addresses of the form user@domain.PROCMAIL, and rewrites those addresses into a mail delivery triple where the mailer is esmtp, the host value is domain, and the user value is user@domain. After rebuilding the configuration with the new master configuration file, running a sendmail -bv test shows the impact of this rewrite rule:

# sendmail -bv crooks@example.com.PROCMAIL

crooks@example.com.PROCMAIL... deliverable: mailer esmtp, host example.com,

user   crooks@example.com