1 # -*- test-case-name: twisted.mail.test.test_mail -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
6 """Support for relaying mail for twisted.mail"""
8 from twisted.mail import smtp
9 from twisted.python import log
10 from twisted.internet.address import UNIXAddress
15 import cPickle as pickle
20 """An SMTP domain which add messages to a queue intended for relaying."""
22 def __init__(self, service, authenticated=False):
23 self.service = service
24 self.authed = authenticated
26 def exists(self, user):
27 """Check whether we will relay
29 Call overridable willRelay method
31 if self.willRelay(user.dest, user.protocol):
32 # The most cursor form of verification of the addresses
33 orig = filter(None, str(user.orig).split('@', 1))
34 dest = filter(None, str(user.dest).split('@', 1))
35 if len(orig) == 2 and len(dest) == 2:
36 return lambda: self.startMessage(user)
37 raise smtp.SMTPBadRcpt(user)
39 def willRelay(self, address, protocol):
40 """Check whether we agree to relay
42 The default is to relay for all connections over UNIX
43 sockets and all connections from localhost.
45 peer = protocol.transport.getPeer()
46 return self.authed or isinstance(peer, UNIXAddress) or peer.host == '127.0.0.1'
48 def startMessage(self, user):
49 """Add envelope to queue and returns ISMTPMessage."""
50 queue = self.service.queue
51 envelopeFile, smtpMessage = queue.createNewMessage()
53 log.msg('Queueing mail %r -> %r' % (str(user.orig), str(user.dest)))
54 pickle.dump([str(user.orig), str(user.dest)], envelopeFile)
61 # XXX - This is -totally- bogus
62 # It opens about a -hundred- -billion- files
63 # and -leaves- them open!
65 def loadMessages(self, messagePaths):
68 for message in messagePaths:
69 fp = open(message+'-H')
71 messageContents = pickle.load(fp)
74 fp = open(message+'-D')
75 messageContents.append(fp)
76 self.messages.append(messageContents)
77 self.names.append(message)
79 def getMailFrom(self):
82 return self.messages[0][0]
87 return [self.messages[0][1]]
89 def getMailData(self):
92 return self.messages[0][2]
94 def sentMail(self, code, resp, numOk, addresses, log):
95 """Since we only use one recipient per envelope, this
96 will be called with 0 or 1 addresses. We probably want
97 to do something with the error message if we failed.
99 if code in smtp.SUCCESS:
100 # At least one, i.e. all, recipients successfully delivered
101 os.remove(self.names[0]+'-D')
102 os.remove(self.names[0]+'-H')
106 class SMTPRelayer(RelayerMixin, smtp.SMTPClient):
107 def __init__(self, messagePaths, *args, **kw):
108 smtp.SMTPClient.__init__(self, *args, **kw)
109 self.loadMessages(messagePaths)
111 class ESMTPRelayer(RelayerMixin, smtp.ESMTPClient):
112 def __init__(self, messagePaths, *args, **kw):
113 smtp.ESMTPClient.__init__(self, *args, **kw)
114 self.loadMessages(messagePaths)