* When we notice a delivery to a user during recipient verification,
take a note of the user's name in the `user' field of the
address_data.
* In the `rcpt_spam' ACL, pick the user name out of the address_data
and remember it and the corresponding recipient address (in a rather
unpleasantly escaped form) along with the others in the variable
`$acl_m_spam_users'.
* Finally, in `data_spam', if we end up rejecting the message, log a
message with the condensed SpamAssassin report, and the user names
and matching recipient addresses.
This leaves, in the rejectlog, enough information for a service to tell
which rejection reports apply to a calling user, and tell them about the
message. We should be able to pick the sender address and the headers
from the usual rejection report, but we don't want to leak the other
envelope recipient addresses. (The user would have seen the /header/
recipients had we not rejected the message as being spam; but the
envelope may contain Bcc recipients or other interesting secrets.)
m4_define(<:SPAMLIMIT_SET:>,
<:address_data = \
${if def:address_data {$address_data}{}} \
m4_define(<:SPAMLIMIT_SET:>,
<:address_data = \
${if def:address_data {$address_data}{}} \
+ m4_ifelse(<:$2:>, <::>, <::>, <:$2 \
+ :>)$1:>)
m4_define(<:SPAMLIMIT_LOOKUP:>,
<:condition = ${if exists{$1}}
SPAMLIMIT_SET(<:${lookup {$2@$3/$4} nwildlsearch {$1} \
m4_define(<:SPAMLIMIT_LOOKUP:>,
<:condition = ${if exists{$1}}
SPAMLIMIT_SET(<:${lookup {$2@$3/$4} nwildlsearch {$1} \
- {SPAMLIMIT_CHECK($value)}}:>):>)
+ {SPAMLIMIT_CHECK(<:$value:>)}}:>, <:$5:>):>)
m4_define(<:SPAMLIMIT_USERV:>,
<:SPAMLIMIT_SET(<:${run {/usr/bin/timeout 5s \
m4_define(<:SPAMLIMIT_USERV:>,
<:SPAMLIMIT_SET(<:${run {/usr/bin/timeout 5s \
SHQUOTE($1) exim-spam-limit \
SHQUOTE($4) \
SHQUOTE($2) SHQUOTE(@$3)} \
SHQUOTE($1) exim-spam-limit \
SHQUOTE($4) \
SHQUOTE($2) SHQUOTE(@$3)} \
- {SPAMLIMIT_CHECK($value)}}:>):>)
+ {SPAMLIMIT_CHECK(<:$value:>)}}:>, <:$5:>):>)
m4_define(<:GET_ADDRDATA:>,
<:extract{<:$1:>}{${if def:address_data{$address_data}{}}}:>)
m4_define(<:GET_ADDRDATA:>,
<:extract{<:$1:>}{${if def:address_data{$address_data}{}}}:>)
${sg {${GET_ADDRDATA(spam_limit){$value}{nil}}} \
{^(|.*\\D.*)\$}{CONF_spam_max}}
${sg {${GET_ADDRDATA(spam_limit){$value}{nil}}} \
{^(|.*\\D.*)\$}{CONF_spam_max}}
+ warn condition = ${GET_ADDRDATA(user){true}{false}}
+ set acl_m_spam_users = \
+ ${if def:acl_m_spam_users {$acl_m_spam_users::}{}}\
+ ${GET_ADDRDATA(user) \
+ {$value=${sg{$local_part@$domain}\
+ {([!:])}{!\$1}}} \
+ fail}
+
## If there's a spam limit already established, and it's different
## from this user's limit, then the sender will have to try this user
## again later.
## If there's a spam limit already established, and it's different
## from this user's limit, then the sender will have to try this user
## again later.
## Undo the escaping.
set acl_m_spam_tests = ${sg{$acl_m_spam_tests}{!(.)}{\$1}}
## Undo the escaping.
set acl_m_spam_tests = ${sg{$acl_m_spam_tests}{!(.)}{\$1}}
- ## If we've decided to reject, then tell the sender to get knotted.
+ ## If we've decided to reject, then leave a dropping in the log file
+ ## so that users can analyse rejections for incoming messages, and
+ ## tell the sender to get knotted.
deny message = Tinned meat product detected ($spam_score)
deny message = Tinned meat product detected ($spam_score)
+ log_message = Spam rejection \
+ score=$spam_score \
+ limit=$acl_m_spam_limit_presentation \
+ tests=$acl_m_spam_tests \
+ users=$acl_m_spam_users
condition = ${if >{$spam_score_int}{$acl_m_spam_limit} \
{true}{false}}
condition = ${if >{$spam_score_int}{$acl_m_spam_limit} \
{true}{false}}
m4_define(<:USER_SPAMLIMIT_ROUTERS:>,
<:USER_SPAMLIMIT_ROUTER(<:lookup:>, <:$1:>,
<:$5SPAMLIMIT_LOOKUP(<:CONF_userconf_dir/spam-limit:>,
m4_define(<:USER_SPAMLIMIT_ROUTERS:>,
<:USER_SPAMLIMIT_ROUTER(<:lookup:>, <:$1:>,
<:$5SPAMLIMIT_LOOKUP(<:CONF_userconf_dir/spam-limit:>,
- <:$2:>, <:$3:>, <:$4:>):>)
+ <:$2:>, <:$3:>, <:$4:>, <:user=$local_part:>):>)
USER_SPAMLIMIT_ROUTER(<:userv:>, <:$1:>,
<:$5SPAMLIMIT_USERV(<:SHQUOTE($local_part):>,
USER_SPAMLIMIT_ROUTER(<:userv:>, <:$1:>,
<:$5SPAMLIMIT_USERV(<:SHQUOTE($local_part):>,
- <:$2:>, <:$3:>, <:$4:>):>):>)
+ <:$2:>, <:$3:>, <:$4:>, <:user=$local_part:>):>):>)
m4_define(<:CURRENT_LOCAL_PART:>,
<:$local_part_prefix$local_part$local_part_suffix:>)
m4_define(<:CURRENT_LOCAL_PART:>,
<:$local_part_prefix$local_part$local_part_suffix:>)