Hack for amavisd-new that can provide for both quarantining and deleting of spam depending on the spam score. Not for use with Maia mailguard. _________________________________________________________________________ Note that as of amavisd-new version 2.3.0 this hack is no longer required. Here are 3 examples the new @spam_quarantine_cutoff_level_maps setting for amavisd-new versions 2.3.0 and greater: $sa_quarantine_cutoff_level = 20.0; @spam_quarantine_cutoff_level_maps = ( new_RE( [qr'^postmaster@example\.com$'i => undef], [qr'^abuse@example\.com$'i => undef], [qr'^(.*)(@[^@])?$'i => 13.999] ), ); @spam_quarantine_cutoff_level_maps = ({ 'postmaster@example.com' => 9999.9, 'abuse@example.com' => 9999.9, 'mr_tiny_quarantine@example.com' => 9.0, '.' => 15.0, }); ________________________________________________________________________ Absolutely no warranty - use at your own risk. mr88talent at yahoo dot com I wanted the ability to quarantine spam that scores an 8.0 or higher and delete spam that scores at 13.999 or higher. In other words, quarantine spam between 8.0 and 13.999 and discard anything higher. This cuts down on the number of emails I have to manually review by about 80%. Amavisd-new allows you to quarantine email marked as spam provided the spam score returned from SpamAssassin ($spam_level) is >= $sa_kill_level_deflt (or $spam_kill_level_ldap or $spam_kill_level_sql) and $spam_quarantine_to (or $spam_quarantine_to_sql or $spam_quarantine_to_ldap) is defined. It also allows you to delete email marked as spam provided $spam_quarantine_to ($spam_quarantine_to_sql $spam_quarantine_to_ldap) is undefined AND $final_spam_destiny is set to D_DISCARD (or D_REJECT or D_BOUNCE) AND the spam score ($spam_level) is >= $sa_kill_level_deflt ($spam_kill_level_ldap $spam_kill_level_sql). I don't use LDAP or SQL so I won't illustrate it further. I set $final_spam_destiny = D_DISCARD; (Despite its name, this only deletes email if the above conditions are met.) I set $spam_quarantine_to = "spams\@$mydomain"; I set $sa_tag_level_deflt = -9999.9; # add spam info headers if at, or above that level $sa_tag2_level_deflt = 5.0; # add 'spam detected' headers at that level $sa_kill_level_deflt = 8.0; # triggers spam evasive actions What this hack does is essentially set $spam_quarantine_to to undefined ( undef ) ONLY if the $spam_level >= 13.999 It does not actually change the value of $spam_quarantine_to, it simply substitutes 'undef' in the following code. The instructions that follow immediately are for version 20030616-p10. Make a backup copy of the executable amavisd (amavisd-new for Debian users). Yours might be /usr/sbin/amavisd-new or /usr/local/sbin/amavisd. Edit the original and search for this section in sub do_spam: for my $r (@{$msginfo->per_recip_data}) { # per-recipient quarantine my($a) = lookup($r->recip_addr, $spam_quarantine_to_sql, $spam_quarantine_to_ldap, $spam_quarantine_to); push(@q_addr, $a) if $a ne '' && !grep {$_ eq $a} @q_addr; } Copy it and edit it so it looks like this: (notice where $spam_quarantine_to is replaced with undef) ###################################### if ($spam_level >= 13.999) { # only seems to work correctly if format is xx.xxx or x.xxx for my $r (@{$msginfo->per_recip_data}) { # per-recipient quarantine my($a) = lookup($r->recip_addr, undef, undef, undef); push(@q_addr, $a) if $a ne '' && !grep {$_ eq $a} @q_addr; } do_log(5, 'Spam level exceeded hard coded level of 13.999 at line 6266 - spam quarantine set to undef'); } else { for my $r (@{$msginfo->per_recip_data}) { # per-recipient quarantine my($a) = lookup($r->recip_addr, $spam_quarantine_to_sql, $spam_quarantine_to_ldap, $spam_quarantine_to); push(@q_addr, $a) if $a ne '' && !grep {$_ eq $a} @q_addr; } } ###################################### Hopefully the basic code logic is clear. If the spam level is at 13.999 or above - execute the modified code - else - - execute the original code. You may want to change do_log(5 to do_log(1 or set $log_level = 5; during testing. I don't suggest you use this on a production system unless you first test it thoroughly but it does work for me. Make sure you study the log files for errors. This has not been tested with per recipient spam quarantines or with LDAP or SQL. I'm guessing this setting overrides all users' settings. ******************************************************************************************** NOTE: A Bug! Due to the way 'sub do_spam' in amavisd-new versions 20040701 and newer is written, sub do_spam does not (cannot) take into account the score boost from the soft whitelist/blacklist settings in @score_sender_maps. This means that this score boost is disregarded in sub do_spam, and once an email is destined to be quarantined, my hack will make a decision to delete a message based solely on the score that SpamAssassin provides. Note that the decision to quarantine or not DOES take into account the score boost. It is only after the decision is made that the boost is ignored. The suggested fix is to upgrade to 2.3.2, so this hack will no longer be required. Version 20030616-p10 did not use soft whitelist/blacklist, and so is unaffected. ******************************************************************************************** With version 20040701: ###################################### if ($spam_level >= 13.999) { # only seems to work correctly if format is xx.xxx or x.xxx # get per-recipient quarantine address(es) and admins for my $r (@{$msginfo->per_recip_data}) { my($rec) = $r->recip_addr; my($q) = lookup(0,$rec, undef); my($a) = lookup(0,$rec, @{ca('spam_admin_maps')}); push(@q_addr, $q) if $q ne '' && !grep {$_ eq $q} @q_addr; push(@a_addr, $a) if $a ne '' && !grep {$_ eq $a} @a_addr; } do_log(5, 'Spam level exceeded hard coded level of 13.999 at line 7269 - spam quarantine set to undef'); } else { # get per-recipient quarantine address(es) and admins for my $r (@{$msginfo->per_recip_data}) { my($rec) = $r->recip_addr; my($q) = lookup(0,$rec, @{ca('spam_quarantine_to_maps')}); my($a) = lookup(0,$rec, @{ca('spam_admin_maps')}); push(@q_addr, $q) if $q ne '' && !grep {$_ eq $q} @q_addr; push(@a_addr, $a) if $a ne '' && !grep {$_ eq $a} @a_addr; } } ###################################### And version 2.1.0-rc4 through 2.1.2: ###################################### if ($spam_level >= 13.999) { # only seems to work correctly if format is xx.xxx or x.xxx # get per-recipient quarantine address(es) and admins for my $r (@{$msginfo->per_recip_data}) { my($rec) = $r->recip_addr; my($q) = $q_method =~ /^bsmtp:/i ? $rec # original recipient when BSMTP : lookup(0,$rec, undef); my($a) = lookup(0,$rec, @{ca('spam_admin_maps')}); push(@q_addr, $q) if $q ne '' && !grep {$_ eq $q} @q_addr; push(@a_addr, $a) if $a ne '' && !grep {$_ eq $a} @a_addr; } do_log(5, 'Spam level exceeded hard coded level of 13.999 at line 7131 - spam quarantine set to undef'); } else { # get per-recipient quarantine address(es) and admins for my $r (@{$msginfo->per_recip_data}) { my($rec) = $r->recip_addr; my($q) = $q_method =~ /^bsmtp:/i ? $rec # original recipient when BSMTP : lookup(0,$rec, @{ca('spam_quarantine_to_maps')}); my($a) = lookup(0,$rec, @{ca('spam_admin_maps')}); push(@q_addr, $q) if $q ne '' && !grep {$_ eq $q} @q_addr; push(@a_addr, $a) if $a ne '' && !grep {$_ eq $a} @a_addr; } } ###################################### And versions 2.2.0 and 2.2.1: ###################################### if ($spam_level >= 13.999) { # only seems to work correctly if format is xx.xxx or x.xxx # get per-recipient quarantine address(es) and admins for my $r (@{$msginfo->per_recip_data}) { my($rec) = $r->recip_addr; my($q); # quarantine (pseudo) address associated with the recipient ($q) = lookup(0,$rec, undef); $q = $rec if $q ne '' && $q_method =~ /^bsmtp:/i; # orig.recip when BSMTP my($a) = lookup(0,$rec, @{ca('spam_admin_maps')}); push(@q_addr, $q) if $q ne '' && !grep {$_ eq $q} @q_addr; push(@a_addr, $a) if $a ne '' && !grep {$_ eq $a} @a_addr; } do_log(5, 'Spam level exceeded hard coded level of 13.999 at line 7434 - spam quarantine set to undef'); } else { # get per-recipient quarantine address(es) and admins for my $r (@{$msginfo->per_recip_data}) { my($rec) = $r->recip_addr; my($q); # quarantine (pseudo) address associated with the recipient ($q) = lookup(0,$rec, @{ca('spam_quarantine_to_maps')}); $q = $rec if $q ne '' && $q_method =~ /^bsmtp:/i; # orig.recip when BSMTP my($a) = lookup(0,$rec, @{ca('spam_admin_maps')}); push(@q_addr, $q) if $q ne '' && !grep {$_ eq $q} @q_addr; push(@a_addr, $a) if $a ne '' && !grep {$_ eq $a} @a_addr; } } ###################################### Hopefully you get the idea.