3 # This module that implements sending mail via QMQP. See
5 # http://cr.yp.to/proto/qmqp.html
7 # for a description of the protocol.
9 # This module was written by Jaakko Niemi <liiwi@lonesom.pp.fi> for
10 # Enemies of Carlotta. It is licensed the same way as Enemies of Carlotta:
15 class QMQPException(Exception):
16 '''Base class for all exceptions raised by this module.'''
18 class QMQPTemporaryError(QMQPException):
19 '''Class for temporary errors'''
20 def __init__(self, msg):
24 return "QMQP-Server said: %s" % self.msg
26 class QMQPPermanentError(QMQPException):
27 '''Class for permanent errors'''
28 def __init__(self, msg):
32 return "QMQP-Server said: %s" % self.msg
34 class QMQPConnectionError(QMQPException):
35 '''Class for connection errors'''
36 def __init__(self, msg):
40 return "Error was: %s" % self.msg
43 '''I handle qmqp connection to a server'''
47 def __init__(self, host = 'localhost'):
50 resp = self.connect(host)
52 def encode(self, stringi):
53 ret = '%d:%s,' % (len(stringi), stringi)
56 def decode(self, stringi):
57 stringi = string.split(stringi, ':', 1)
58 stringi[1] = string.rstrip(stringi[1], ',')
59 if len(stringi[1]) is not int(stringi[0]):
60 print 'malformed netstring encounterd'
63 def connect(self, host = 'localhost'):
64 for sres in socket.getaddrinfo(host, 628, 0, socket.SOCK_STREAM):
65 af, socktype, proto, canonname, sa = sres
67 self.sock = socket.socket(af, socktype, proto)
70 print 'connect failed'
80 def send(self, stringi):
83 self.sock.sendall(stringi)
84 except socket.error, err:
86 raise QMQPConnectionError, err
92 self.file = self.sock.makefile('rb')
94 line = self.file.readline()
99 line = self.decode(line)
105 def sendmail(self, from_addr, to_addrs, msg):
107 msg = self.encode(msg)
108 from_addr = self.encode(from_addr)
110 # I don't understand why len(to_addrs) <= 1 needs to be handled differently.
111 # Anyway, it doesn't seem to work with Postfix. --liw
112 # if len(to_addrs) > 1:
114 # recipients = recipients + self.encode(t)
116 # recipients = self.encode(to_addrs[0])
119 recipients = recipients + self.encode(t)
120 output = self.encode(msg + from_addr + recipients)
122 ret = self.getreply()
126 raise QMQPTemporaryError, ret[1:]
128 raise QMQPPermanentError, ret[1:]
130 if __name__ == '__main__':
132 maili = 'asfasdfsfdasfasd'
133 envelope_sender = 'liw@liw.iki.fi'
134 recips = [ 'liw@liw.iki.fi' ]
135 retcode = a.sendmail(envelope_sender, recips, maili)