Not quite swingin', but... | Main | Mutt Codeless Language Module for BBEdit

September 10, 2004

Add to Your Remote SpamAssassin Whitelist from Mail.app (with a mutt digression)

Posted by Mike on September 10, 2004 5:37 PM

Score one for server-side living.

This is a simple script I wrote to add selected messages in Mail.app to the SpamAssassin whitelist on a remote server. It has two companions I'm still poking at that report messages as ham or spam to the SpamAssassin bayesian learner.

The problem it solves is pretty straightforward:

I have a laptop and a desktop. I use the desktop system a lot more, but the laptop gets pulled out now and then. Mail.app is nice, but its bayesian learner isn't all that, and it can't share filter and spam information between different computers (without hacking some "copy the files from here to there" sort of gimcrackery that I don't want to deal with).

So the obvious answer is going to the server and letting it take over: procmail to handle mail sorting, SpamAssassin to handle spam filtering, IMAP to present the sorted, filtered mail in a sensible folder scheme.

The obvious problem is that some of SpamAssassin's features (like reporting spam messages, teaching it which messages are ham, and whitelisting false positives you trust) are living on the server, which Mail.app doesn't know much about.

It gets worse when you get mail from a lot of people who routinely send stuff that looks a lot like spam by the average spam filter: I know that I'm interested in the latest breakthrough wonder self-emulating recursive XML-based technology from FooBitz, but most people should be grateful that SpamAssassin typically doesn't and marks such correspondence as at least a tentative spam.

Fortunately, Mail.app has a scripting menu and a decent AppleScript dictionary, so to maintain a remote spamassassin whitelist, all one really needs is:

That's what this script does. It reads every selected message in Mail.app, extracts the "from" address, and passes that address off to a very simple shell command that looks like this:

ssh foo@bar -t spamassassin --add-addr-to-whitelist=goodguy@foobar.com

After it runs the shell command, it makes sure the whitelisted message is marked as not-spam by Mail.app.

Optionally, it tosses up a list of the addresses it added to your whitelist so you can be assured that "Ansible T. Cadillac" the herbal v.1.a.g.r.A! dealer didn't get into your whitelist by mistake.

It's in the documentation, but another quick, cool note: By tacking on three underscores (_) and a command string (like "ctl-w") then saving the script in your ~/Library/Scripts/Mail Scripts folder, you can invoke the script from the keyboard instead of going up to the mail scripting menu with the mouse.

And one other thing:

I solved this problem with mutt (which can do IMAP if you like) in slightly different fashion by adding this line to my .muttrc: macro pager .w "| ssh me@foo 'spamassassin -aW'\nd"

That binds the key strokes ".w" to a mutt command that pipes the the message into ssh and tells spamassassin on the server side to whitelist the addresses in the message. (Thanks, Sam, for reminding me how to pipe stuff over ssh.)

It took, it should be obvious, a lot less effort to cook that up in mutt than it did to write the AppleScript to make Mail.app to do the same thing.

I'm still wavering on which client to use, by the way. Mail.app's pretty slick, but mutt's got its own attractions in the form of speed and flexibility.

--Open this script in a new Script Editor window.

-- Remote report of whitelist address to SpamAssassin from Mail.app
-- This is most handy if saved in your Mail scripting menu ($HOME:Library:Scripts:Mail Scripts)
-- If you want to add a shortcut, save it with a filename ending in something like "___ctl-w" (that's three underscore characters)

-- Set this variable to your username and the remote host on which you run SpamAssassin
set user to "mph@ix"
set addies to {}

tell application "Mail"
    
    set l to the selection as list
    repeat with m in l
        
        try
            set wladdress to the sender of m
            set wladdress to extract address from wladdress
            do shell script "ssh " & user & " -t spamassassin --add-addr-to-whitelist=" & wladdress
            set addies to wladdress & return & addies
            set junk mail status of m to false
        end try
    end repeat
    
    -- optional and potentially annoying... commented out for now:
    --    display dialog ("These addresses were added to your whitelist:" & addies) buttons {"OK"} default button "OK"
    
end tell