Anti-Spam filtering always has one thread: False positives. If you tighten the anti spam rules too much, then probably you get some legal mails classified as spam and maybe even thrown away without ever having seen them. But there is a way out by using socalled whitelists

But those whitelists do have their own problems. It is quite easy to forge any sender. Or, even worse, a person we know and trust may get a virus, which then sends spam in the name of that person. This is an absolutely common scenario. o what we need is a bulletproof whitelist system which makes it impossible for any virus to forge a valid mail and thus pass the anti-spam machinery.

Well, there already is such a system: GPG, the Gnu Privacy Guard. With GPG you can sign your messages. Such a signed mail is for sure from the person from whom it seems to be, if the signature can be verified. For (hopefulle) it is necessary to enter a pass phrase to sign the message, a virus has no chance to send valid spam mails.

In most cases Procmail will be used for mail filtering. So this will deal with how to embed this system within procmail.

Deconstruction of a signed mail

Return-Path: <> X-Original-To: siegfried@localhost Delivered-To: siegfried@localhost Received: from localhost (localhost []) by (Postfix) with ESMTP id 6B65153C12E for <siegfried@localhost>; Mon, 25 Sep 2006 14:32:08 +0200 (CEST) Delivery-Date: Mon, 25 Sep 2006 14:30:51 +0200 Received-SPF: none (mxeu2: is neither permitted nor denied by domain of client-ip=;;; Received: from [] by localhost with POP3 (fetchmail-6.3.2) for <siegfried@localhost> (single-drop); Mon, 25 Sep 2006 14:32:08 +0200 (CEST) Received: from [] ( by (node=mxeu2) with ESMTP (Nemesis), id 0MKpdM-1GRpbn2ZgR-0000WU for; Mon, 25 Sep 2006 14:30:51 +0200 Received: from [] (helo=noname) by (node=mrelayeu0) with ESMTP (Nemesis), id 0MKwh2-1GRpbn16Mi-00082X; Mon, 25 Sep 2006 14:30:51 +0200 From: Siegfried Gipp <> To: Subject: gpg test Date: Mon, 25 Sep 2006 14:30:41 +0200 User-Agent: KMail/1.9.1 MIME-Version: 1.0 Content-Type: multipart/signed; boundary="nextPart17568337.dOXm5l1bdW"; protocol="application/pgp-signature"; micalg=pgp-sha1 Content-Transfer-Encoding: 7bit Message-Id: <> X-UIDL: D*Q!!Z<>!!R"X"!7XD!! X-UID: Status: R X-Status: NC X-KMail-EncryptionState: X-KMail-SignatureState: X-KMail-MDN-Sent: --nextPart17568337.dOXm5l1bdW Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline test test =2D-=20 public gpg key at --nextPart17568337.dOXm5l1bdW Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2.2 (GNU/Linux) iD8DBQBFF8v7XiMHTxkL1hkRArVTAJ9RS2jB+M9SI2Zfaqi1ShRGfL377gCgyoDf +BVMjM8rOBCfYBtZurKOob4= =UV3c -----END PGP SIGNATURE----- --nextPart17568337.dOXm5l1bdW--

This is a testmail i sent to myself. The relevant parts are marked. Some lines where deleted.

The ideas here need a working installation of gpg as prerequisite. Additionally any valid keys hve to be entered into the key ring and signed.

First, the signed e-mail has to be detected as such and then fed into some program. Unfortnately it is not possible to feed the mail directly into gpg. For gpg to verify the mail, the text block to verify and the signature have to be in separate files.

Procmail receipe

# Signierte mails :0 H * ^Content-Type: multipart/signed * ? $HOME/gpgchk { LOG="GPG signature verified " :0 $DEFAULT }

This receipe first checks for a mail header marking this mail as a signed mail. If this header is found, then the mail is fed into a shell script, which then verifies the signature. This procmail receipe should be placed in the very first place so that any further checking may be skipped, if verification was positive.


#!/bin/sh ID=$RANDOM cat > mail_$ID.txt BOUNDARY=`cat mail_$ID.txt | fgrep "boundary=" | cut -d'"' -f2` cat mail_$ID.txt | formail -I "" | sed -e "1,/$BOUNDARY/ d"\ | sed -e "/$BOUNDARY/ q"\ | head -n -2\ | sed "s/$/\r/" > body_$ID.txt cat mail_$ID.txt\ | sed -ne "/-----BEGIN PGP SIGNATURE-----/, /-----END PGP SIGNATURE-----/ p" | sed "s/$/\r/" > sig_$ID.asc gpg --verify sig_$ID.asc body_$ID.txt RC=$? rm mail_$ID.txt rm body_$ID.txt rm sig_$ID.asc exit $RC

This shellscript now separates the message body from the signature. This creates three temporary files in the home directory of the user: A copy of the complete mail, the pure message body and the signature. The latter ones are then used by gpg to verify the signature. After verification the three temporary files are removed and the return code is returned back to procmail. A successful verification returns a 0. In this case the action configured in this procmail receipe is executed. The mail is delivered.

More options

This system may be used as anti phishing tool. Let's assume my bankdecides to sign all their mails with gpg. If i then install the public key of that bank locally on my mail server, valid mails from this bank will always get through the spam filter, regardless of the contents. And for me it is now easy to simply throw away any mail from that bank which is not signed or does not have a valid signature. This simply needs a second procmail receipe after the gpg check:

:0 H * ^From: /dev/null

Now any mail from that bank which does not have a valid signature or no signature at all is forwardedto the general data nirvana. Sadly, today the banks are not able to sign their messages.

Home control

Another use of this system is home control. Since these signed messages are secure, you may use signed mails to remote control cour house. The mail might contain ordersor scripts to be executed on that server. Given the proper hardware you might then switch on the heater or the prepared oven, or yu may request data from your hose. All this secure.