Package: python2.3-twisted Version: 1.3.0-5 Severity: normal Tags: patch
Hi. Twisted 1.3 contains two bad mail-related bugs, which are really harmful for my application scalemail:
- insufficient error handling in mail delivery, causing mail loss (fixed by r12036)
- unable to send mail from <> (fixed by r12767, which broke receiving mail from <>, which is fixed in r12858).
Attached are the the SVN commits, rediffed to apply nicely to 1.3.0-5. I have tested them, and I am the original author for r12767 and r12858.
I'd really love it if you could upload a twisted 1.3.0-6 with these changes.
diff -Naur twisted-1.3.0.orig/twisted/protocols/smtp.py twisted-1.3.0/twisted/protocols/smtp.py --- twisted-1.3.0.orig/twisted/protocols/smtp.py 2004-04-09 06:06:54.000000000 +0300 +++ twisted-1.3.0/twisted/protocols/smtp.py 2005-01-12 10:32:24.000000000 +0200 @@ -419,6 +419,9 @@ host = DNSNAME portal = None + # Control whether we log SMTP events + noisy = True + # A factory for IMessageDelivery objects. If an # avatar implementing IMessageDeliveryFactory can # be acquired from the portal, it will be used to @@ -656,8 +659,9 @@ self.mode = COMMAND return self.sendCode(354, 'Continue') - fmt = 'Receiving message for delivery: from=%s to=%s' - log.msg(fmt % (origin, [str(u) for (u, f) in recipients])) + if self.noisy: + fmt = 'Receiving message for delivery: from=%s to=%s' + log.msg(fmt % (origin, [str(u) for (u, f) in recipients])) def connectionLost(self, reason): # self.sendCode(421, 'Dropping connection.') # This does nothing... @@ -667,7 +671,10 @@ if self.mode is DATA: try: for message in self.__messages: - message.connectionLost() + try: + message.connectionLost() + except: + log.err() del self.__messages except AttributeError: pass @@ -694,8 +701,8 @@ return defer.DeferredList([ m.eomReceived() for m in self.__messages - ]).addCallback(self._messageHandled - ).addErrback(self._messageNotHandled) + ], consumeErrors=True).addCallback(self._messageHandled + ) del self.__messages return line = line[1:] @@ -726,19 +733,20 @@ message.connectionLost() state_DATA = dataLineReceived - def _messageHandled(self, _): - self.sendCode(250, 'Delivery in progress') - log.msg('Accepted message for delivery') - - def _messageNotHandled(self, failure): - if failure.check(SMTPServerError): - self.sendCode(failure.value.code, failure.value.resp) - fmt = 'Message not handled: (%d) %s' - log.msg(fmt % (failure.value.code, failure.value.resp)) + def _messageHandled(self, resultList): + failures = 0 + for (success, result) in resultList: + if not success: + failures += 1 + log.err(result) + if failures: + msg = 'Could not send e-mail' + L = len(resultList) + if L > 1: + msg += ' (%d failures out of %d recipients)' % (failures, L) + self.sendCode(550, msg) else: - self.sendCode(550, 'Could not send e-mail') - log.msg('Message not handled: (550) Could not send e-mail') - log.err(failure) + self.sendCode(250, 'Delivery in progress') def _cbAuthenticated(self, (iface, avatar, logout)): if issubclass(iface, IMessageDeliveryFactory):
diff -Naur twisted-1.3.0.r12036/twisted/mail/protocols.py twisted-1.3.0/twisted/mail/protocols.py --- twisted-1.3.0.r12036/twisted/mail/protocols.py 2003-10-08 05:06:44.000000000 +0300 +++ twisted-1.3.0/twisted/mail/protocols.py 2005-01-12 10:36:44.000000000 +0200 @@ -70,7 +70,7 @@ def validateFrom(self, helo, origin): if not helo: raise smtp.SMTPBadSender(origin, 503, "Who are you? Say HELO first.") - if not origin.domain: + if origin.local != '' and origin.domain == '': raise smtp.SMTPBadSender(origin, 501, "Sender address must contain domain.") return origin diff -Naur twisted-1.3.0.r12036/twisted/protocols/smtp.py twisted-1.3.0/twisted/protocols/smtp.py --- twisted-1.3.0.r12036/twisted/protocols/smtp.py 2005-01-12 10:32:24.000000000 +0200 +++ twisted-1.3.0/twisted/protocols/smtp.py 2005-01-12 10:35:54.000000000 +0200 @@ -334,7 +334,7 @@ self.local = ''.join(local) self.domain = ''.join(domain) - if self.domain == '': + if self.local != '' and self.domain == '': if defaultDomain is None: defaultDomain = DNSNAME self.domain = defaultDomain @@ -358,7 +358,10 @@ return ''.join(res) def __str__(self): - return '@'.join((self.local, self.domain)) + if self.local or self.domain: + return '@'.join((self.local, self.domain)) + else: + return '' def __repr__(self): return "%s.%s(%s)" % (self.__module__, self.__class__.__name__, diff -Naur twisted-1.3.0.r12036/twisted/test/test_mail.py twisted-1.3.0/twisted/test/test_mail.py --- twisted-1.3.0.r12036/twisted/test/test_mail.py 2004-03-13 18:27:12.000000000 +0200 +++ twisted-1.3.0/twisted/test/test_mail.py 2005-01-12 10:36:05.000000000 +0200 @@ -378,6 +378,10 @@ origin = smtp.Address('<[EMAIL PROTECTED]>') self.failUnless(self.D.validateFrom(helo, origin) is origin) + helo = ('hostname', '1.2.3.4') + origin = smtp.Address('<>') + self.failUnless(self.D.validateFrom(helo, origin) is origin) + self.assertRaises( smtp.SMTPBadSender, self.D.validateFrom, None, origin diff -Naur twisted-1.3.0.r12036/twisted/test/test_smtp.py twisted-1.3.0/twisted/test/test_smtp.py --- twisted-1.3.0.r12036/twisted/test/test_smtp.py 2004-01-19 23:04:53.000000000 +0200 +++ twisted-1.3.0/twisted/test/test_smtp.py 2005-01-12 10:35:48.000000000 +0200 @@ -427,6 +427,8 @@ ['[EMAIL PROTECTED]', '<[EMAIL PROTECTED]>'], ['"User Name" <[EMAIL PROTECTED]>', '<[EMAIL PROTECTED]>'], [smtp.Address('[EMAIL PROTECTED]'), '<[EMAIL PROTECTED]>'], + ['', '<>'], + [smtp.Address(''), '<>'], ] for (c, e) in cases: