Procmail: Numeric Threshold Example

One of the mail headers added by SpamAssassin is “X-Spam-Score”.  It provides a real number value as an alternative to its graphically represented “X-Spam-Level” header.  E.g.:

X-Spam-Score: 3.673
X-Spam-Level: ***

This header can be used in conjunction with the following Procmail recipe to send messages that exceed a threshold spam score value to a quarantine folder for separate review. Note that procmail recipes can be notoriously bewildering, and I’m certainly no expert, but I’ve been using this successfully so far.

####
# begin quarantine
#
SPAM_QUARANTINE=".IN_spam/"
SPAM_THRESHOLD=7.0

:0
*   ^X-Spam-Score:.*\/[-0-9\.]+
{
    :0:
    * $ -${SPAM_THRESHOLD}^0
    * $  ${MATCH}^0
    ${SPAM_QUARANTINE}
}
# end quarantine
####

While this is not intended as a procmail tutorial, here is a brief explanation of what this does.

####
#  begin quarantine
[...]
# end quarantine
####

Lines beginning with “#” are comments.

SPAM_QUARANTINE="IN_spam/"
SPAM_THRESHOLD=7.0

Variable/constant assignments. It’s not necessary to use variables for this, but it’s a best practices sort of habit. SPAM_QUARANTINE is the destination IMAP folder where matching messages will be filed.  (The trailing “/” is an artifact of the IMAP server that stores messages in maildir format where each message is stored as its own file in a directory. YMMV)

SPAM_THRESHOLD should be self-explanatory. I’d start with a relatively high value, then tune it downwards as you become more familiar with how your instance of SpamAssassin tends to score your messages.  Since X-Spam-Score is not a standard header, you will probably need to be able to display full mail headers for whichever email client you use to view it.

:0

Starts the recipe.

*    ^X-Spam-Score:.\/[-0-9\.]+

Look for the X-Spam-Score: header.  Assign everything to the right of “\/” to the built in $MATCH dummy variable.  “[-0-9\.]+” is the regular expression that matches one or more digits/decimal points/negative signs.  It’s not the strictest regexp, but it’s probably the simplest one that gets the job done.

:0:
{
    [...]
}

A sub-recipe with a local lockfile.  I’m not sure the local lockfile is necessary, but it’s probably a conservative choice.

    * $ -${SPAM_THRESHOLD}^0
    * $  ${MATCH}^0

Weighted scores conditions that effectively implement “if $MATCH > $SPAM_THRESHOLD”

    ${SPAM_QUARANTINE}

If all prior conditions have matched, the message is saved here.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: