[Spambayes] popget.py - Gnus mail fetcher

Paul Moore lists@morpheus.demon.co.uk
Sun Nov 17 16:50:56 2002


I use Gnus on Windows for my mailreader at home, with Hamster (a local
mail/news server) as my POP3 mailbox. I could use pop3proxy for spam
detection, but it has a couple of problems:

1. As I already have a local POP server, I have to use a non-standard
   port
2. I have to remember to start the program, or package it up as a
   service, or otherwise automate the startup and hide the console
   window.

Rather than this, I wrote a small program (attached) to grab the
contents of a POP mailbox into a local file, scoring messages as it
goes. I can then put the following in my .gnus.el file to run my mail
through spambayes. It's equally usable on Unix, for people who have
reasons for not wanting to use pop3proxy there.

--- .gnus.el snippet ---
;; Popget program from spambayes setup
(setq popget "C:\\Data\\spambayes\\spambayes-test\\popget.bat")

;; Get mail via POP3
(setq mail-sources
      '((pop :server "localhost"
	     :user "XXXXXX"
	     :password "XXXXXX"
	     :program (concat popget " -u %u/%p -P %P -s %s -f %t"))))
------------------------

This works beautifully, and combined with XEmacs mail splitting, I
have a nice spam detection facility. With a little bit of work (not
hard) I can also use the new hammiefilter.py to add training
keystrokes, and I have quite a nice setup.

One other thing I'm going to add is a way to display the spam clues
for the current message in a buffer. When I'm done, I'll package up
the code in a form that can be included in the project as a sample
Gnus setup.

Paul.

-------------- next part --------------
#!/usr/bin/env python

# A program to get and classify the contents of a POP3 mailbox.

"""Usage: %(program)s [options]

Where:
    -h
        Show usage and exit
    -s SERVER
        The server from which to get the mail (default localhost)
    -P PORT
        The port to use (default 110)
    -u USER/PASS
        The username and password of the POP3 account
    -f FILE
        The file to save messages in (defaults to stdout)
    -k
        Keep messages on the POP server (default is to delete them)
    -p FILE
        use file as the persistent store.  loads data from this file if it
        exists, and saves data to this file at the end.
        Default: %(DEFAULTDB)s
    -d
        use the DBM store instead of cPickle.  The file is larger and
        creating it is slower, but checking against it is much faster,
        especially for large word databases. Default: %(USEDB)s
    -D
        the reverse of -d: use the cPickle instead of DBM
"""

import os
import sys
import getopt
import poplib
import socket
import hammie
from Options import options

try:
    True, False
except NameError:
    # Maintain compatibility with Python 2.2
    True, False = 1, 0

# For usage(); referenced by docstring above
program = sys.argv[0]
DEFAULTDB = options.persistent_storage_file

class Config:
    def __init__(self):
        self.server = 'localhost'
        self.port = 110
        self.user = None
        self.password = None
        self.DB = DEFAULTDB
        self.use_db = options.persistent_use_database
        self.filename = "<stdout>"
        self.file = sys.stdout
        self.delete = True

    def createhammie(self):
        bayes = hammie.createbayes(self.DB, self.use_db)
        self.hammie = hammie.Hammie(bayes)

FROMLINE = "From popget@spambayes.org Sat Jan 31 00:00:00 2000"

def getmail(conf):
    pop = poplib.POP3(conf.server, conf.port)
    if conf.user:
        pop.user(conf.user)
    if conf.password:
        pop.pass_(conf.password)

    n, size = pop.stat()
    num = 1
    while num <= n:
        rsp, lines, size = pop.retr(num)
        msg = "\n".join(lines)
        print >>conf.file, FROMLINE
        print >>conf.file, conf.hammie.filter(msg)
        print >>conf.file
        if conf.delete:
            pop.dele(num)
        num += 1
    pop.quit()

def usage(code, msg=''):
    """Print usage message and sys.exit(code)."""
    if msg:
        print >> sys.stderr, msg
        print >> sys.stderr
    print >> sys.stderr, __doc__ % globals()
    sys.exit(code)

def main():
    """Main program - parse options and run."""
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hs:P:u:f:kp:dD")
    except getopt.error, msg:
        usage(2, msg)

    if not opts:
        usage(2, "No options given")

    conf = Config()

    for opt, arg in opts:
        if opt == '-h':
            usage(0)
        elif opt == '-s':
            conf.server = arg
        elif opt == '-P':
            try:
                conf.port = int(arg)
            except ValueError:
                usage(2, "Port must be a number ('%s' given)" % arg)
        elif opt == '-u':
            try:
                conf.user, conf.password = arg.split("/",1)
            except ValueError:
                usage(2, "-u option is USER/PASS ('%s' given)" % arg)
        elif opt == '-k':
            conf.delete = False
        elif opt == '-f':
            # Need to expand ~
            conf.filename = os.path.expanduser(arg)
            conf.file = open(conf.filename, "w")
        elif opt == '-p':
            conf.DB = arg
        elif opt == '-d':
            conf.use_db = True
        elif opt == '-D':
            conf.use_db = False

    conf.createhammie()
    try:
        getmail(conf)
    except (poplib.error_proto, socket.error), e:
        print >> sys.stderr, "POP protocol error %s" % e
        sys.exit(1)

if __name__=="__main__":
    main()
-------------- next part --------------

-- 
This signature intentionally left blank


More information about the Spambayes mailing list