The per.ly weblog of Ian Norton
Random header image... Refresh for more!

Exim & spam assassin – rejecting spam at different scores

So I’ve spent some time researching how to implement rejection of spam at different scores based on the recipients of a given message.

http://wiki.exim.org/ExiscanExamples#Having_multiple_content_scanning_profiles_for_several_users_or_domains

We didn’t like options A or B and option C isn’t sensible in this day and age.

Option D. For a given message, reject at the highest score for the given list of recipients. If a@example.com has a reject of 18, and b@example.com has a reject of 25 then a message sent to both will have a reject of 25. This isn’t ideal and it certainly doesn’t provide the detailed per user settings potentially available within spam assassin, but it’s certainly a reasonable compromise.

So, how do we do this?

Let’s define an expansion variable that we can re-use:


SPAM_REJECT_SCORE = ${lookup {${lc:$local_part@$domain}} lsearch* {/etc/spam-reject-scores} }

From this, we can see that we’re using a plain text aliases style file with a search for a default value if no match is found (that’s what the * does):


b@example.com: 25
*: 18

Now we add the following to the acl_smtp_rcpt (which may be called something different, find the ‘acl_smtp_rcpt =’ line in your config) ACL:


# If the acl_m0 isn't set, get the value from SPAM_REJECT_SCORE and set it.
accept condition = ${if def:acl_m0 {0}{1}}
set acl_m0 = SPAM_REJECT_SCORE

# If the SPAM_REJECT_SCORE value is higher than acl_m0, set it to the value from SPAM_REJECT_SCORE
accept set acl_m0 = ${if > {SPAM_REJECT_SCORE} {${acl_m0}} \
{SPAM_REJECT_SCORE} \
{${acl_m0}} \
}

Shiny! Now we need to do something with it to reject messages, so this is what I’ve got in my acl_smtp_data (which again might be named differently):


# Reject spam at high scores - value is an INTEGER!!!!
deny message = This message scored $spam_score spam points.
log_message = exceeded spam threshold with $spam_score points.
spam = nobody:true
condition = ${if >{$spam_score_int}{${eval:$acl_m0 * 10}}{1}{0}}

You’ll notice that the value is multiplied by 10 to turn it into an integer for comparison with the value returned by spam assassin. This bit me first time I tried to do this.

So testing should give you something like this:


[root@localhost ~]# exim -bh 209.85.229.17
..
220 localhost.localdomain ESMTP Exim 4.69 Tue, 23 Feb 2010 09:34:09 +0000
helo mail.google.com
250 localhost.localdomain Hello ww-in-f17.1e100.net [209.85.229.17]
MAIL FROM: bob@example.com
250 OK
RCPT TO: a@example.com
..
>>> processing "accept"
>>> check condition = ${if def:acl_m0 {0}{1}}
>>> = 1
>>> check set acl_m0 = ${lookup {${lc:$local_part@$domain}} lsearch* {/etc/spam-reject-scores} }
>>> = 18
>>> accept: condition test succeeded
250 Accepted
DATA
354 Enter message, ending with "." on a line by itself
Subject: !!!!!!PENIS ENLARGEMMENT!!!!11!!! cialis levitra soma
To: a@example.com
From: "Pammer, S"

Test SMTP session
GET YOUR VIAGRA HERE!!!!!!!!!! PORNOGRAPHY
see the attached file for details
viagra express Online Pharmacy No prescription needed No prescription needed
.
...
>>> processing "deny"
>>> check spam = nobody:true
>>> check condition = ${if >{$spam_score_int}{${eval:$acl_m0 * 10}}{1}{0}}
>>> = 1
>>> deny: condition test succeeded
>>> unspool_mbox(): unlinking '/var/spool/exim/scan/1NjrI5-0000FW-Ow/1NjrI5-0000FW-Ow.eml'
550 This message scored 20.4 spam points.
LOG: 1NjrI5-0000FW-Ow H=ww-in-f17.1e100.net (mail.google.com) [209.85.229.17] F= rejected after DATA: exceeded spam threshold with 20.4 points.

Similar test to b@example.com finishes with:


>>> processing "deny"
>>> check spam = nobody:true
>>> check condition = ${if >{$spam_score_int}{${eval:$acl_m0 * 10}}{1}{0}}
>>> = 0
>>> deny: condition test failed
>>> processing "accept"
>>> accept: condition test succeeded
>>> unspool_mbox(): unlinking '/var/spool/exim/scan/1NjrKA-0000FZ-Q8/1NjrKA-0000FZ-Q8.eml'
LOG: 1NjrKA-0000FZ-Q8 <= bob@example.com H=ww-in-f17.1e100.net (mail.google.com) [209.85.229.17] P=smtp S=1941 from for b@example.com
250 OK id=1NjrKA-0000FZ-Q8


**** SMTP testing: that is not a real message id!

No pink meat was harmed in the making of this post….. :)

0 comments

There are no comments yet...

Kick things off by filling out the form below.

Leave a Comment