OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.mail.test.test_mail -*- | |
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
3 # See LICENSE for details. | |
4 | |
5 | |
6 """Support for relaying mail for twisted.mail""" | |
7 | |
8 from twisted.mail import smtp | |
9 from twisted.python import log | |
10 from twisted.internet.address import UNIXAddress | |
11 | |
12 import os | |
13 | |
14 try: | |
15 import cPickle as pickle | |
16 except ImportError: | |
17 import pickle | |
18 | |
19 class DomainQueuer: | |
20 """An SMTP domain which add messages to a queue intended for relaying.""" | |
21 | |
22 def __init__(self, service, authenticated=False): | |
23 self.service = service | |
24 self.authed = authenticated | |
25 | |
26 def exists(self, user): | |
27 """Check whether we will relay | |
28 | |
29 Call overridable willRelay method | |
30 """ | |
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) | |
38 | |
39 def willRelay(self, address, protocol): | |
40 """Check whether we agree to relay | |
41 | |
42 The default is to relay for all connections over UNIX | |
43 sockets and all connections from localhost. | |
44 """ | |
45 peer = protocol.transport.getPeer() | |
46 return self.authed or isinstance(peer, UNIXAddress) or peer.host == '127
.0.0.1' | |
47 | |
48 def startMessage(self, user): | |
49 """Add envelope to queue and returns ISMTPMessage.""" | |
50 queue = self.service.queue | |
51 envelopeFile, smtpMessage = queue.createNewMessage() | |
52 try: | |
53 log.msg('Queueing mail %r -> %r' % (str(user.orig), str(user.dest))) | |
54 pickle.dump([str(user.orig), str(user.dest)], envelopeFile) | |
55 finally: | |
56 envelopeFile.close() | |
57 return smtpMessage | |
58 | |
59 class RelayerMixin: | |
60 | |
61 # XXX - This is -totally- bogus | |
62 # It opens about a -hundred- -billion- files | |
63 # and -leaves- them open! | |
64 | |
65 def loadMessages(self, messagePaths): | |
66 self.messages = [] | |
67 self.names = [] | |
68 for message in messagePaths: | |
69 fp = open(message+'-H') | |
70 try: | |
71 messageContents = pickle.load(fp) | |
72 finally: | |
73 fp.close() | |
74 fp = open(message+'-D') | |
75 messageContents.append(fp) | |
76 self.messages.append(messageContents) | |
77 self.names.append(message) | |
78 | |
79 def getMailFrom(self): | |
80 if not self.messages: | |
81 return None | |
82 return self.messages[0][0] | |
83 | |
84 def getMailTo(self): | |
85 if not self.messages: | |
86 return None | |
87 return [self.messages[0][1]] | |
88 | |
89 def getMailData(self): | |
90 if not self.messages: | |
91 return None | |
92 return self.messages[0][2] | |
93 | |
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. | |
98 """ | |
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') | |
103 del self.messages[0] | |
104 del self.names[0] | |
105 | |
106 class SMTPRelayer(RelayerMixin, smtp.SMTPClient): | |
107 def __init__(self, messagePaths, *args, **kw): | |
108 smtp.SMTPClient.__init__(self, *args, **kw) | |
109 self.loadMessages(messagePaths) | |
110 | |
111 class ESMTPRelayer(RelayerMixin, smtp.ESMTPClient): | |
112 def __init__(self, messagePaths, *args, **kw): | |
113 smtp.ESMTPClient.__init__(self, *args, **kw) | |
114 self.loadMessages(messagePaths) | |
OLD | NEW |