comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:7f4443127958
1 # Simple milter deamon that handles email messages off to spamd for
2 # classification. Messages classified as spam are rejected. Other
3 # are augmented with Spamassassin additional headers.
4
5 import email.parser
6 from cStringIO import StringIO
7
8 import Milter as milter
9 import spamc
10
11
12 # headers to add to scanned messages
13 HEADERS = ('X-Spam-Checker-Version', 'X-Spam-Level', 'X-Spam-Status', )
14
15
16 class Milter(milter.Base):
17
18 def __init__(self):
19 # integer incremented with each call
20 self.id = milter.uniqueID()
21 self.fd = StringIO()
22
23 @milter.noreply
24 def connect(self, hostname, family, hostaddr):
25 self.hostname = hostname
26 self.hostaddr = hostaddr
27 return milter.CONTINUE
28
29 def hello(self, heloname):
30 self.helo = heloname
31 return milter.CONTINUE
32
33 def envfrom(self, mailfrom, *str):
34 self.mailfrom = mailfrom
35 return milter.CONTINUE
36
37 @milter.noreply
38 def envrcpt(self, recipient, *str):
39 self.recipient = recipient
40 return milter.CONTINUE
41
42 @milter.noreply
43 def header(self, name, val):
44 # add header to buffer
45 self.fd.write('%s: %s\n' % (name, val))
46 return milter.CONTINUE
47
48 @milter.noreply
49 def eoh(self):
50 # terminate headers
51 self.fd.write('\n')
52 return milter.CONTINUE
53
54 @milter.noreply
55 def body(self, chunk):
56 # add body to buffer
57 self.fd.write(chunk)
58 return milter.CONTINUE
59
60 def eom(self):
61 # ask spamd about the received message
62 self.conn = spamc.Client('localhost')
63 resp = self.conn.request('HEADERS', self.fd.getvalue())
64 # reject spam messages
65 if resp.result:
66 return milter.REJECT
67 # parse returned message headers
68 data = resp.read()
69 print data
70 headers = email.parser.Parser().parsestr(data)
71 # add headers
72 for name in HEADERS:
73 # transform multiple line headers to single line ones
74 value = ' '.join(headers.get(name, '').split())
75 self.addheader(name, value)
76 # accept message
77 return milter.ACCEPT
78
79 def close(self):
80 # clean up
81 self.fd.close()
82 self.conn.close()
83 return milter.CONTINUE
84
85 def abort(self):
86 # client disconnected prematurely
87 return milter.CONTINUE
88
89
90 def main():
91 socketname = "/var/spool/postfix/private/spamc"
92 timeout = 600
93
94 # register the milter factory
95 milter.factory = Milter
96 # ask milter features we use
97 milter.set_flags(milter.CHGHDRS + milter.ADDHDRS)
98 # run
99 milter.runmilter("spamc-milter", socketname, timeout)
100
101
102 if __name__ == "__main__":
103 main()