My Exim configuration is largely based on the one from struction.de
(
http://struction.de/projects/HOWTO_VirtualMail_Exim-MySQL-Spamassassin-ClamAV-Dovecot/index?set_style=clean),
although I have my 'acl_check_data' and local delivery transport pasted
below.
My problem is that mail is getting rejected because it gets a positive
spamassassin score, and apparently is only accepted when it gets a
*negative* score. It seems that the ACL is not actually sending
information about the score of the scanned mail to the transport like it
should (or at least, as I expect it to). In the transport, mail is
delivered to the user based on whether the spamassassin score is lower
than the score the user saves to the mysql database. Although this may
just be the *wrong* way of going about it.
So without further ado, my configuration:
acl_check_data:
# Add headers to all messages (:true). Before enabling this,
# you must install SpamAssassin. You may also need to set the spamd_address
# option above.
#
warn message = X-Spam-Score: $spam_score\n\
X-Spam-Score-Int: $spam_score_int\n\
X-Spam-Bar: $spam_bar\n\
X-Spam-Report: $spam_report\n\
X-Spam-Threshold: ${lookup mysql{ \
SELECT score \
FROM spam_settings \
WHERE
email='${quote_mysql:$local_part@$domain}'
\
}{$value}{7}}
!authenticated = *
condition = ${if < {$message_size}{SPAM_FILESIZE_LIMIT}}
spam = spamassassin:true
# set acl_m8 = X-Spam-Score: $spam_score
# Deny messages that seem to have timeouts during spam-scan
warn message = Temporary error while spam-scanning. Please try
again later. Message ID: $message_exim_id
log_message = message temporarily rejected, because of
spam-scan error (maybe timeout)
!authenticated = *
condition = ${if < {$message_size}{SPAM_FILESIZE_LIMIT}}
condition = ${if !def:spam_score}
# Reject spam messages with score over the customer-defined threshold
deny message = This message is classified as spam, and
therefore rejected. Message ID: $message_exim_id
!authenticated = *
condition = ${if >={$spam_score_int}{${lookup mysql{\
SELECT score AS spam_reject_threshold \
FROM spam_settings \
WHERE
email='${quote_mysql:$local_part@$domain}'
\
}{$value}{15}}}{true}{false}}
spam = spamassassin:true
# delay = 20s
# temporary reject message for greylisting, if integer spamscore is
above GREYLIST_SPAM_THRESHOLD
# and the message (sender address + IP) is seen for the first time.
# Authenticated users skip this.
deny message = Your Message will be greylisted!
log_message = message from ${sender_address} over
[${sender_host_address}] will be greylisted as it scores $spam_score
spam points
!authenticated = *
condition = ${if
>={$spam_score_int}{GREYLIST_SPAM_THRESHOLD}{true}{false}}
# false, if triple is in db (at this point if it's in the timeout has
expired)
# true, if not
condition = ${lookup mysql{ \
SELECT MAX(first_seen) \
FROM greylist \
WHERE SenderIP = '${quote_mysql:$sender_host_address}' \
AND SenderAddress = '${quote_mysql:$sender_address}' \
}{false}{true}}
# insert triple into database (which should succeed)
condition = ${lookup mysql{ \
INSERT INTO greylist ( SenderIP, SenderAddress, first_seen ) \
VALUES ( '${quote_mysql:$sender_host_address}',
'${quote_mysql:$sender_address}', UNIX_TIMESTAMP() ) \
}{$value}fail}
# log, if mail successfully passed greylisting
warn message = X-GreyList: Message successfully passed
GreyListing after $acl_m0 seconds.
log_message = message from ${sender_address} over
[${sender_host_address}] with HELO ($sender_helo_name)
successfully passed GreyListing after $acl_m0 seconds and scores
$spam_score spam points
!authenticated = *
# true, if triple is in db (at this point if it's in the timeout
has expired)
# false, if not
condition = ${lookup mysql{ \
SELECT MAX(first_seen) \
FROM greylist \
WHERE SenderIP = '${quote_mysql:$sender_host_address}' \
AND SenderAddress = '${quote_mysql:$sender_address}' \
}{true}{false}}
set acl_m0 = ${eval:$tod_epoch-${lookup mysql{ \
SELECT MAX(first_seen) \
FROM greylist \
WHERE SenderIP = '${quote_mysql:$sender_host_address}' \
AND SenderAddress = '${quote_mysql:$sender_address}' \
}{$value}}}
warn message = X-Date: $tod_log\n\
X-Connected-IP: $sender_host_address:$sender_host_port
# save additional information in header
warn message = X-Message-Linecount: $message_linecount\n\
X-Body-Linecount: $body_linecount\n\
X-Message-Size: $message_size\n\
X-Body-Size: $message_body_size\n\
X-Local-Recipient-Count: $rcpt_count
warn log_message = DEBUG load_avgx1000: $load_average spam_score:
$spam_score message_size: $message_size
# finally accept the message in DATA ACL.
accept
## [snip]
local_mysql_delivery:
driver = appendfile
directory = /home/${domain}/${local_part}/Maildir/
maildir_format
delivery_date_add
envelope_to_add
return_path_add
user = mail
group = mail
mode = 0660
headers_remove = Subject : X-Spam-Flag : X-Spam-Score-Int : X-Spam-Score
: X-Spam-Bar : X-Spam-Report
headers_add = "X-Spam-Threshold: $header_X-Spam-Threshold:\n\
X-Spam-Score: $header_X-Spam-Score:\n\
X-Spam-Score-Int: $header_X-Spam-Score-Int:\n\
X-Spam-Bar: $header_X-Spam-Bar:\n\
X-Spam-Report: $header_X-Spam-Report:\n\
X-Spam-Flag: ${if def:header_X-Spam-Score-Int:{\
${if
>={${eval:${sg{$header_X-Spam-Score-Int:}{^.*\n}{}}}}\
{${lookup mysql{ \
SELECT score \
FROM spam_settings \
WHERE
email='${quote_mysql:$local_part@$domain}'
\
}{$value}{ERROR}}}{YES}{NO}}\
}{\
UNKNOWN\
}}\n\
Subject: ${if def:header_X-Spam-Score-Int:{\
${if
>={${eval:${sg{$header_X-Spam-Score-Int:}{^.*\n}{}}}}\
{${lookup mysql{ \
SELECT score \
FROM spam_settings \
WHERE
email='${quote_mysql:$local_part@$domain}'
\
}{$value}{ERROR}}}{${lookup
mysql{ \
SELECT score \
FROM spam_settings \
WHERE
email='${quote_mysql:$local_part@$domain}'
\
}{$value}{ERROR}}$h_subject:}{$h_subject:}}\
}{$h_subject:}}\n\
X-Delivered-To: $original_local_part@$original_domain
($local_part@$domain)\n\
X-Message-Age: $message_age"