diff spamc-milter.py @ 0:7f4443127958 default tip

Import
author Daniele Nicolodi <daniele@grinta.net>
date Wed, 02 Nov 2011 12:03:09 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spamc-milter.py	Wed Nov 02 12:03:09 2011 +0100
@@ -0,0 +1,103 @@
+# Simple milter deamon that handles email messages off to spamd for
+# classification.  Messages classified as spam are rejected.  Other
+# are augmented with Spamassassin additional headers.
+
+import email.parser
+from cStringIO import StringIO
+
+import Milter as milter
+import spamc
+
+
+# headers to add to scanned messages
+HEADERS = ('X-Spam-Checker-Version', 'X-Spam-Level', 'X-Spam-Status', )
+
+
+class Milter(milter.Base):
+
+    def __init__(self):
+        # integer incremented with each call
+        self.id = milter.uniqueID()
+        self.fd = StringIO()
+
+    @milter.noreply
+    def connect(self, hostname, family, hostaddr):
+        self.hostname = hostname
+        self.hostaddr = hostaddr
+        return milter.CONTINUE
+
+    def hello(self, heloname):
+        self.helo = heloname
+        return milter.CONTINUE
+
+    def envfrom(self, mailfrom, *str):
+        self.mailfrom = mailfrom
+        return milter.CONTINUE
+
+    @milter.noreply
+    def envrcpt(self, recipient, *str):
+        self.recipient = recipient
+        return milter.CONTINUE
+
+    @milter.noreply
+    def header(self, name, val):
+        # add header to buffer
+        self.fd.write('%s: %s\n' % (name, val))
+        return milter.CONTINUE
+
+    @milter.noreply
+    def eoh(self):
+        # terminate headers
+        self.fd.write('\n')
+        return milter.CONTINUE
+
+    @milter.noreply
+    def body(self, chunk):
+        # add body to buffer
+        self.fd.write(chunk)
+        return milter.CONTINUE
+
+    def eom(self):
+        # ask spamd about the received message
+        self.conn = spamc.Client('localhost')
+        resp = self.conn.request('HEADERS', self.fd.getvalue())
+        # reject spam messages
+        if resp.result:
+            return milter.REJECT
+        # parse returned message headers
+        data = resp.read()
+        print data
+        headers = email.parser.Parser().parsestr(data)
+        # add headers
+        for name in HEADERS:
+            # transform multiple line headers to single line ones
+            value = ' '.join(headers.get(name, '').split())
+            self.addheader(name, value)
+        # accept message
+        return milter.ACCEPT
+
+    def close(self):
+        # clean up
+        self.fd.close()
+        self.conn.close()
+        return milter.CONTINUE
+
+    def abort(self):
+        # client disconnected prematurely
+        return milter.CONTINUE
+
+
+def main():
+    socketname = "/var/spool/postfix/private/spamc"
+    timeout = 600
+
+    # register the milter factory
+    milter.factory = Milter
+    # ask milter features we use
+    milter.set_flags(milter.CHGHDRS + milter.ADDHDRS)
+    # run
+    milter.runmilter("spamc-milter", socketname, timeout)
+
+
+if __name__ == "__main__":
+    main()