Spam Filtering with Qmail, Procmail, and SpamAssassin in Plesk 9+
A while back, Chris Beach published a hack for spam filtering with Qmail, Procmail, and SpamAssassin in a Plesk installation. Even though Plesk usies SpamAssassin to tag emails as spam, it doesn’t filter spam emails out of the inbox prior to delivery. Chris’ hack used procmail to read the spam level of an email and deliver spam emails to a dedicated Spam folder.
Starting with version 9.0, Plesk switched from using custom, Plesk-only installations of programs like SpamAssassin to using system-wide installations of these programs. As a result of the switch, it’s now easier to upgrade these programs independently of Plesk. Unfortunately, the switch also breaks hacks like the one above.
This hack re-enables spam filtering in Plesk 9+.
.qmail
Each user has a custom .qmail file located in /var/qmail/mailnames/YOURDOMAIN/USER/.qmail. Qmail reads this file each time it processes an email for delivery. Qmail doesn’t do anything useful to the email other than deliver it, so we’ll need to send the email to procmail for processing.
By default, the .qmail file looks like this:
| true | /usr/bin/deliverquota ./Maildir
This delivers an email to USER’s mailbox while respecting any existing quotas placed on the size of the mailbox.
Change the .qmail file to this:
| true |preline /usr/bin/procmail -m -o .procmailrc
Qmail now passes the email off to procmail.
.procmailrc
In the same directory, create a .procmailrc file if it does not exist. Put the following code into the .procmailrc file (make sure to replace YOURDOMAIN and USER with the proper values:
MAILDIR=/var/qmail/mailnames/YOURDOMAIN/USER/Maildir
DEFAULT=${MAILDIR}/
SPAMDIR=${MAILDIR}/.Spam/
TRASHDIR=${MAILDIR}/.Trash/
# RECIPE 1 -- Pipe message to SpamAssassin
# The "f" flag indicates to procmail that this pipe recipe is a "filter" which "delivers" filtered emails to the specified command, here SpamAssassin, and ends prevents further processing of the email by procmail
# The "w" flag indicates to procmail that it should wait for the piped command to return before it further processes the email
# The "-R" flag tells SpamAssassin to provide a spam report for all emails
# Use "-r" instead to generate a report only for spam emails
# SpamAssassin outputs the spam report for the email to stdout, but we can redirect this data to an environmental variable for later use by procmail by prepending the pipe with VARIABLE=
:0 fw
REPORT=| /usr/bin/spamc -R
# RECIPE 2 -- Append the spam report to the email
# We use formail to add the spam report as a header to the email message
# We can refer to the variable storing the spam report by using the "$" symbol right before the variable
:0 fw
*
| formail -I "X-Spam-Report: $REPORT"
# RECIPE 3 -- Delete Obvious Spam
# Any message with a ridiculously high spam level is simply deleted without wasting the user's time or space.
# Tweak the number of "\*"'s as needed.
:0 f:
* ^X-Spam-Level: \*\*\*\*\*
/dev/null
# RECIPE 4 -- Deliver potential false-positives and other low-rated spam to the Spam folder
:0 f:
* ^X-Spam-Status: Yes.*
${SPAMDIR}
# Everything else goes through!
# This section is actually redundant, since procmail will deliver the email to the user's inbox once it runs out of recipes to apply.
# You may want to use deliverquota here instead because procmail will not honor any mailbox quotas when it delivers the message.
:0:
*
${DEFAULT}
Thanks for this great solution
I’m actually looking into getting procmail (with plesk 9) to just move all the spam to my .Spam folder, and mark it read. Also, I have fail2ban messages which I would like to move and mark read as well (subject is always marked [Fail2Ban]). Any suggestions on that?
spamc -R doesn’t seem to output the X-Spam-Level header, onlye the estatus then the report, thus the next recipe doesnt seem to work, I have spamassasin 3.2.5