Tweaking my dspam setup

I was recently disappointed with my dspam setup: while it was catching lots of spam and it would never misclassify ham, I would still get like 50 spams a day in my inbox.

In a moment of enlightenment, I realised that it could be because I'm subscribed to loads of mailing lists many of which I read only every so often. This means that I don't feed dspam those spam messages that manage to go through those lists, and so dspam gets to figure out that they are innocent, and therefore ends up with too broad an idea of innocence.

The solution was heroically simple: plug dspam only after sorting mailing lists in their own folders, and only on the remaining personal mail.

Not so simple was the implementation, since I had dspam integrated with postfix and it would necessarily process all the mail I get.

This is what I did:

  1. I removed dspam hooks from postfix
  2. I hooked dspam into procmail:

    :0fw
    | /usr/bin/dspam --user=enrico --stdout --deliver=innocent,spam
    
    :0
    * ^X-DSPAM-Result: spam
    .spam/
    
  3. I figured out that dspam run from postfix in that way would not make use of the server, not even if I use --client. I thus disabled the dspam server in /etc/default/dspam. This is a shame, but luckily I don't have many users and the server load won't suffer much.

  4. I fixed the privileges under /var/spool/dspam so that the users can read their dspam data but not the data of other users. Here's what I conjured:

    drwxrwxr-x dspam  dspam /var/spool/dspam/
    drwxrwxr-x dspam  dspam /var/spool/dspam/data
    drwxrwxr-x dspam  dspam /var/spool/dspam/data/local
    drwxrwx--- enrico dspam /var/spool/dspam/data/local/enrico
    drwxrwx--- enrico dspam /var/spool/dspam/data/local/enrico/enrico.sig
    -rw-rw---- enrico dspam /var/spool/dspam/data/local/enrico/enrico.*
    drwxrwx--- pippo  dspam /var/spool/dspam/data/local/pippo [...]
    drwxrwx--- pluto  dspam /var/spool/dspam/data/local/pluto [...]
    drwxrwxr-x dspam  dspam /var/spool/dspam/opt-in
    drwxrwxr-x dspam  dspam /var/spool/dspam/opt-in/local
    -rw-rw-r-- dspam  dspam /var/spool/dspam/opt-in/local/enrico.dspam
    -rw-rw-r-- dspam  dspam /var/spool/dspam/opt-in/local/pippo.dspam
    -rw-rw-r-- dspam  dspam /var/spool/dspam/opt-in/local/pluto.dspam
    -rw-rw---- dspam  dspam /var/spool/dspam/system.log
    

    the opt-in files are actually empty files and dspam seems to only stat() them, so they are probably ok even if they're not readable by users.

    This setup of permissions should allow dspam to run as the various users while fully preserving their privacy towards each others.

  5. In /etc/dspam/dspam.conf I commented out the Delivery options, since I let procmail take care of the delivery. I'm also not using ParseToHeaders anymore. The rest of the dspam configuration did not change.

  6. Instead of ParseToHeaders, I set up postfix aliases properly running dspam as the dspam user. The trick is to create an alias file owned by the dspam user and the dspam group, and tell postfix to use it:

    alias_maps = hash:/etc/aliases, hash:/etc/postfix/aliases-dspam
    alias_database = hash:/etc/aliases, hash:/etc/postfix/aliases-dspam
    

    /etc/postfix/aliases-dspam in turn contains:

    spam-enrico:"|/usr/bin/dspam --user enrico --class=spam --source=error"
    notspam-enrico:"|/usr/bin/dspam --user enrico --class=innocent --source=error"
    spam-pippo:"|/usr/bin/dspam --user pippo --class=spam --source=error"
    notspam-pippo:"|/usr/bin/dspam --user pippo --class=innocent --source=error"
    spam-pluto:"|/usr/bin/dspam --user pluto --class=spam --source=error"
    notspam-pluto:"|/usr/bin/dspam --user pluto --class=innocent --source=error"
    

    since I took care of leaving everything in /var/spool/dspam writable by the dspam group, this works perfectly.

    It also allows me to bounce a mail to the report address instead of forwarding it. With ParseToHeaders I had to forward because the bounced messages would not have the report address in their headers, and so dspam could not identify them.

    By the way, here's the mutt macro I use to report spam:

    macro index,pager <F12> "bspam-enrico@xxx.xx\n\ns=.spam\n" 'Report as spam'
    

This is it. It took a while as dspam isn't always straightforward to set up, but now I've finally stopped having to remove 20 spam messages from my inbox for every 1 legitimate mail I receive.