[tor-commits] [bridgedb/develop] Replace rfc822 with email.message

phw at torproject.org phw at torproject.org
Wed Feb 19 18:27:17 UTC 2020


commit 1138daa8e1202d1649a70c7b238ac7ebcade23a8
Author: Damian Johnson <atagar at torproject.org>
Date:   Fri Jan 10 16:13:01 2020 -0800

    Replace rfc822 with email.message
    
    Hardest part of this migration yet. Python 2's deprecated rfc8222 module was
    removed in python 3. Unfortunately Isis used a catch-all here, covering the
    fact that this code has always been a bit broken (due to overriding our 'addr'
    import with a local variable)...
    
      Traceback (most recent call last):
        File "/home/atagar/Desktop/tor/bridgedb/bridgedb/test/test_email_autoresponder.py", line 353, in test_SMTPAutoresponder_getMailFrom_givemebridges_at_seriously
          recipient = str(self.responder.getMailFrom())
        File "/home/atagar/Desktop/tor/bridgedb/bridgedb/distributors/email/autoresponder.py", line 535, in getMailFrom
          raise addr.BadEmail(allRecipients)
      builtins.AttributeError: 'str' object has no attribute 'BadEmail'
    
    Finally the single test that exercises this code path works...
    
      before: FAILED (skips=109, failures=24, errors=225, successes=623)
      after:  FAILED (skips=109, failures=23, errors=225, successes=624)
---
 bridgedb/distributors/email/autoresponder.py | 19 ++++++++++---------
 bridgedb/distributors/email/server.py        | 12 ++++--------
 bridgedb/test/test_email_dkim.py             |  4 ++--
 bridgedb/test/test_email_server.py           |  6 +++---
 4 files changed, 19 insertions(+), 22 deletions(-)

diff --git a/bridgedb/distributors/email/autoresponder.py b/bridgedb/distributors/email/autoresponder.py
index 1d2b618..3711eae 100644
--- a/bridgedb/distributors/email/autoresponder.py
+++ b/bridgedb/distributors/email/autoresponder.py
@@ -39,6 +39,7 @@ Functionality for autoresponding to incoming emails.
 from __future__ import unicode_literals
 from __future__ import print_function
 
+import email
 import io
 import logging
 import time
@@ -439,8 +440,8 @@ class SMTPAutoresponder(smtp.SMTPClient):
 
         if not body: return  # The client was already warned.
 
-        messageID = self.incoming.message.getheader("Message-ID", None)
-        subject = self.incoming.message.getheader("Subject", None)
+        messageID = self.incoming.message.get("Message-ID", None)
+        subject = self.incoming.message.get("Subject", None)
         response = generateResponse(recipient, client,
                                     body, subject, messageID,
                                     self.incoming.context.gpgSignFunc)
@@ -461,13 +462,13 @@ class SMTPAutoresponder(smtp.SMTPClient):
         """
         clients = []
         addrHeader = None
-        try: fromAddr = self.incoming.message.getaddr("From")[1]
+        try: fromAddr = email.utils.parseaddr(self.incoming.message.get("From"))[1]
         except (IndexError, TypeError, AttributeError): pass
         else: addrHeader = fromAddr
 
         if not addrHeader:
             logging.warn("No From header on incoming mail.")
-            try: senderHeader = self.incoming.message.getaddr("Sender")[1]
+            try: senderHeader = email.utils.parseaddr(self.incoming.message.get("Sender"))[1]
             except (IndexError, TypeError, AttributeError): pass
             else: addrHeader = senderHeader
         if not addrHeader:
@@ -509,10 +510,10 @@ class SMTPAutoresponder(smtp.SMTPClient):
 
         try:
             ourAddress = smtp.Address(self.incoming.context.fromAddr)
-            allRecipients = self.incoming.message.getaddrlist("To")
+            allRecipients = self.incoming.message.get_all("To")
 
-            for _, addr in allRecipients:
-                recipient = smtp.Address(addr)
+            for address in allRecipients:
+                recipient = smtp.Address(address)
                 if not ourAddress.domain in recipient.domain:
                     logging.debug(("Not our domain (%s) or subdomain, skipping"
                                    " email address: %s")
@@ -525,11 +526,11 @@ class SMTPAutoresponder(smtp.SMTPClient):
                                    " email address: %s") % str(recipient))
                     continue
                 # Only check the username before the first '+':
-                beforePlus = recipient.local.split('+', 1)[0]
+                beforePlus = recipient.local.split(b'+', 1)[0]
                 if beforePlus == ourAddress.local:
                     ours = str(recipient)
             if not ours:
-                raise addr.BadEmail(allRecipients)
+                raise addr.BadEmail('No email address accepted, please see log', allRecipients)
 
         except Exception as error:
             logging.error(("Couldn't find our email address in incoming email "
diff --git a/bridgedb/distributors/email/server.py b/bridgedb/distributors/email/server.py
index 0f96812..8a2fbea 100644
--- a/bridgedb/distributors/email/server.py
+++ b/bridgedb/distributors/email/server.py
@@ -49,10 +49,10 @@ Servers which interface with clients and distribute bridges over SMTP.
 
 from __future__ import unicode_literals
 
+import email.message
 import logging
 import io
 import socket
-import rfc822
 
 from twisted.internet import defer
 from twisted.internet import reactor
@@ -222,7 +222,7 @@ class SMTPMessage(object):
         if self.nBytes > self.context.maximumSize:
             self.ignoring = True
         else:
-            self.lines.append(line)
+            self.lines.append(line.decode('utf-8') if isinstance(line, bytes) else line)
         if not safelog.safe_logging:
             try:
                 ln = line.rstrip("\r\n").encode('utf-8', 'replace')
@@ -251,12 +251,8 @@ class SMTPMessage(object):
         :rtype: :api:`twisted.mail.smtp.rfc822.Message`
         :returns: A ``Message`` comprised of all lines received thus far.
         """
-        rawMessage = io.StringIO()
-        for line in self.lines:
-            line = line.decode('utf-8') if isinstance(line, bytes) else line
-            rawMessage.writelines(line + '\n')
-        rawMessage.seek(0)
-        return rfc822.Message(rawMessage)
+
+        return email.message_from_string('\n'.join(self.lines))
 
 
 @implementer(smtp.IMessageDelivery)
diff --git a/bridgedb/test/test_email_dkim.py b/bridgedb/test/test_email_dkim.py
index e8fe3f3..2330a71 100644
--- a/bridgedb/test/test_email_dkim.py
+++ b/bridgedb/test/test_email_dkim.py
@@ -11,8 +11,8 @@
 
 """Unittests for the :mod:`bridgedb.distributors.email.dkim` module."""
 
+import email.message
 import io
-import rfc822
 
 from twisted.trial import unittest
 
@@ -47,7 +47,7 @@ get bridges
 
     def _createMessage(self, messageString):
         """Create an ``email.message.Message`` from a string."""
-        messageIO = io.StringIO(messageString if isinstance(messageString, str) else messageString.decode('utf-8'))
+        messageIO = io.StringIO(unicode(messageString))
         return rfc822.Message(messageIO)
 
     def test_checkDKIM_good(self):
diff --git a/bridgedb/test/test_email_server.py b/bridgedb/test/test_email_server.py
index bc331f4..081a0e4 100644
--- a/bridgedb/test/test_email_server.py
+++ b/bridgedb/test/test_email_server.py
@@ -13,10 +13,10 @@
 
 from __future__ import print_function
 
+import email.message
 import socket
 import string
 import types
-import rfc822
 
 from twisted.python import log
 from twisted.internet import defer
@@ -95,10 +95,10 @@ class SMTPMessageTests(unittest.TestCase):
                               defer.Deferred)
 
     def test_SMTPMessage_getIncomingMessage(self):
-        """``getIncomingMessage`` should return a ``rfc822.Message``."""
+        """``getIncomingMessage`` should return a ``email.message.Message``."""
         self.message.lineReceived(self.line)
         self.assertIsInstance(self.message.getIncomingMessage(),
-                              rfc822.Message)
+                              email.message.Message)
 
 
 class SMTPIncomingDeliveryTests(unittest.TestCase):





More information about the tor-commits mailing list