How to Implement Custom Bad Word Filtering in SpamAssassin and Auto-Route Spam to Dedicated Folder


2 views

To add custom bad word filtering in SpamAssassin, edit your local.cf file (typically at /etc/mail/spamassassin/local.cf) with header and body rules:

header CUSTOM_BAD_WORDS Subject =~ /viagra|cialis|sex|xxx|penis|porn|gambling|casino/i
body CUSTOM_BAD_WORDS /viagra|cialis|sex|xxx|penis|porn|gambling|casino/i
score CUSTOM_BAD_WORDS 3.0
describe CUSTOM_BAD_WORDS Contains prohibited words

The real challenge comes in ensuring filtered messages actually go to the Spam folder. Here's how to modify your maildrop filter:

if (/^X-Spam-Level: \*{5,}/ || /^X-Spam-Status: Yes/)
{
    # Check if Spam folder exists
    test -d $VHOME/Maildir/.Spam
    if ($RETURNCODE != 0)
    {
        # Create Spam folder if missing
        maildirmake -f Spam $VHOME/Maildir 2>/dev/null
        test -x /usr/bin/subscribeIMAP.sh && /usr/bin/subscribeIMAP.sh Spam $VHOME
    }
    
    # Deliver to Spam folder with quota check
    exception {
        to "$VHOME/Maildir/.Spam"
    }
}

For automatic Spam folder creation for new accounts, add this to your maildrop global filter:

test -d $VHOME/Maildir
if ($RETURNCODE == 0)
{
    test -d $VHOME/Maildir/.Spam
    if ($RETURNCODE != 0)
    {
        maildirmake -f Spam $VHOME/Maildir
        test -x /usr/bin/subscribeIMAP.sh && /usr/bin/subscribeIMAP.sh Spam $VHOME
    }
}

For more precise filtering, combine multiple conditions:

if (/^X-Spam-Level: \*{5,}/ || /^X-Spam-Status: Yes/ || 
    /^Subject: .*\b(viagra|cialis|porn)\b/i)
{
    # Existing spam handling code
    ...
}

If messages still appear in inbox:

  1. Verify maildrop is actually processing messages (/var/log/maildrop/maildrop.log)
  2. Check SpamAssassin headers are being added (grep X-Spam /var/log/maillog)
  3. Test folder permissions (ls -ld /home/vpopmail/domains/*/Maildir/.Spam)

After examining your configuration files, I see you've successfully implemented basic bad word filtering in SpamAssassin through local.cf, but the automatic sorting mechanism needs refinement. The current setup marks messages but doesn't properly route them to the Spam folder due to maildrop filter behavior.

First, let's optimize your SpamAssassin rules in /etc/mail/spamassassin/local.cf:


# Enhanced bad word rules with proper regex syntax
header   BAD_WORD_HEADER   Subject =~ /\\b(viagra|cialis|sex|xxx|penis|pussy|greekajob|perazdera)\\b/i
body     BAD_WORD_BODY     /\\b(viagra|cialis|sex|xxx|penis|pussy|greekajob|perazdera)\\b/i
meta     BAD_WORD_COMBINED BAD_WORD_HEADER || BAD_WORD_BODY
score    BAD_WORD_COMBINED 5.0
describe BAD_WORD_COMBINED Contains prohibited adult content

The critical changes needed in /etc/mail/mailfilter:


# Improved spam handling logic
if(/^X-Spam-Status: Yes, score=([0-9]+)\\.([0-9]+)/:h || /^X-Spam-Flag: YES/:h)
{
    # Ensure Spam folder exists
    test -d $VHOME/Maildir/.Spam
    if($RETURNCODE == 1)
    {
        exception {
            maildirmake -f Spam $VHOME/Maildir
            test -x /usr/bin/subscribeIMAP.sh && /usr/bin/subscribeIMAP.sh Spam $VHOME
        }
    }

    # Deliver to Spam folder with quota check
    exception {
        to "$VHOME/Maildir/.Spam/"
    }
    log "***SPAM*** delivered to Spam folder"
    exit
}

For automatic Spam folder creation for new accounts, add this to your maildrop filter before message processing:


# Create standard folders for new accounts
test -d $VHOME/Maildir/.Spam
if($RETURNCODE == 1)
{
    maildirmake -f Spam $VHOME/Maildir
    test -x /usr/bin/subscribeIMAP.sh && /usr/bin/subscribeIMAP.sh Spam $VHOME
}

After making these changes:
1. Restart SpamAssassin: systemctl restart spamassassin
2. Test with: spamassassin -t < testmessage.eml
3. Verify maildrop processing: maildrop -V9 -d username < testmessage.eml

For better spam handling, consider these additional measures in local.cf:


# Bayesian filtering optimization
use_bayes          1
bayes_auto_learn   1
bayes_auto_learn_threshold_nonspam 0.1
bayes_auto_learn_threshold_spam    6.0

# Network tests
use_razor2         1
use_pyzor          1
use_dcc            1