Orange is my favorite color

Some notes that I don’t want to forget to follow-up on my March (Q)mail Server Madness post earlier this year. Things are running great with the exception of SpamAssassin being pretty useless. An SA rules update in the last couple of weeks has been quarantining every email from Facebook plus another 25% of my legitimate email so we’ve disabled it and we’re just letting DSPAM do it’s thing instead. Here’s a couple of tweaks we’ve made:

Upgrade to CHKUSER 2.0.9

CHKUSER 2.0.9 includes one update that is very important to us: CHKUSER_DISABLE_VARIABLE. This enhancements allows us to disable CHKUSER checks for certain relays. In our case, our web application servers relay mail and sometimes the TO address is invalid. Without this change, CHKUSER would deny even sending the email so bad emails would queue up on the web servers. What we want to happen is for the mail server to accept them, bounce them and let our bounce handling routines run notifying the sender of the bad address. Here’s the necessary steps:

  1. Download development package qmail-toaster-1.03-1.3.21.src.rpm which includes the CHKUSER 2.0.9 code and a few other enhancements (see this thread)
  2. rpm -Uvh qmail-toaster-1.03-1.3.21.src.rpm
  3. bunzip2 /usr/src/redhat/SOURCES/qmailtoaster-1.3.2.patch.bz2
  4. vi /usr/src/redhat/SOURCES/qmailtoaster-1.3.2.patch
  5. Search for “/* #define CHKUSER_DISABLE_VARIABLE” and remove the comments, save
  6. Search for “/* #define CHKUSER_ENABLE_USERS_EXTENSIONS” and remove the comments to re-enable dash-aliasing
  7. bzip2 /usr/src/redhat/SOURCES/qmailtoaster-1.3.2.patch
  8. cd /usr/src/redhat/SPECS
  9. rpmbuild -bb –with cnt50 –target i686 qmail-toaster.spec
  10. rpm -Uvh /usr/src/redhat/RPMS/i686/qmail-toaster-1.3.2.rpm

Note, I’m running on x64 CentOS 5. For some reason I had to specify the target as i686 as without the target it wanted to generate an i386 binary while everything else is i686. I didn’t know if that would cause problems so I specified the target explicitly.

For any IP address we want to bypass the CHKUSER checks, we simply add an entry to /etc/tcprules.d/tcp.smtp with a RELAYCLIENT variable. An entry might look like:,RELAYCLIENT=""

Finally, the RPM update for qmail-toaster overrides your SSL certificates for SMTP. To restore my real certificates, I had to perform the following steps (lifted from

# cp /etc/httpd/certs/ /var/qmail/control/servercert.pem
# ln -s /var/qmail/control/servercert.pem /var/qmail/control/clientcert.pem
# chown -h qmaild:root /var/qmail/control/clientcert.pem
# chmod 400 /var/qmail/control/servercert.pem
# qmailctl restart is simply a single concatenated file containing your key, certificate and any intermediate certificates (required for registrars like Go Daddy for example):

# cat /path/to/ssl_cert.key /path/to/ssl_cert.crt /path/to/gd_intermediate_bundle.crt > /var/qmail/control/servercert.pem

Updated Mailfilter Script

We also expanded our mailfilter script to be a little bit smarter and handle DSPAM better. Here’s the latest:

import EXT
import HOST

VUSER=`echo ${EXT%-*}`
export VUSER
USERHOME=`/mail/bin/vuserinfo -d [email protected]$HOST`

MARKTIME=`date +%s.%N`
UNIQUE=`date +%N`

logfile "/var/log/maildrop/mailfilter.log"

# Test for the existance of the Junk directory.  Create it if it doesn't exist
log "[email protected]$HOST[$UNIQUE] : Start user filter"

# make sure the Junk folder exists and is subscribed too
`test -d $USERHOME/Maildir/.Junk`

if ( $RETURNCODE == 1 )
    `/usr/bin/maildirmake -f Junk $USERHOME/Maildir`
    `echo INBOX.Junk >> $USERHOME/Maildir/courierimapsubscribed`

# make sure the retrain folder exists
`test -d $USERHOME/Maildir/.JunkRetrain`

if ( $RETURNCODE == 1 )
    `/usr/bin/maildirmake -f JunkRetrain $USERHOME/Maildir`
    `echo INBOX.JunkRetrain >> $USERHOME/Maildir/courierimapsubscribed`

# now analyze the SA header
if (/^X-Spam-Status: Yes/)
        log "[email protected]$HOST[$UNIQUE] : SpamAssassin found SPAM"
        to "$USERHOME/Maildir/.Junk"
        # spamassassin thinks its ham, which means nothing, because SA sucks
        # so now we check with dspam

        # warning: exception must have one space and then the curly bracket or else syntax errors are generatead
        exception {
                xfilter "/usr/local/bin/dspam --deliver=innocent,spam --stdout --user $USERHOME"

        if (/^X-DSPAM-Result: Spam/)
                # dspam says spam
                log "[email protected]$HOST[$UNIQUE] : DSPAM found SPAM"
                to "$USERHOME/Maildir/.Junk"
                # ham in both places, deliver
                log "[email protected]$HOST[$UNIQUE] : DSPAM found HAM (returncode = $RETURNCODE)"
                if (/^X-DSPAM-Result: Innocent/)
                        log "[email protected]$HOST[$UNIQUE] : HAM includes X-DSPAM-Result: Innocent"
                        if (/^X-DSPAM-Result: Whitelisted/)
                                log "[email protected]$HOST[$UNIQUE] : HAM includes X-DSPAM-Result: Whitelisted"
                                log "[email protected]$HOST[$UNIQUE] : HAM does NOT include X-DSPAM-Result: Innocent/Whitelisted"
                to "$USERHOME/Maildir/"

Since we’re dropping SpamAssassin, this file could be streamlined to be DSPAM specific but it doesn’t hurt to leave it in the event we decide to re-enable it at a later date. Simply save the script somewhere and enable it via a .qmail file in a user directory with the following:

|preline /usr/bin/maildrop /path/to/mailfilter-to-spam-plus-dspam

Comments are closed.