email: remove `header` option to get_address.
[pygrader.git] / pygrader / email.py
index aeb4da8e742a353a1f5f00cd31f74047971c8a72..c04732fb641a73425963d5d4c5ee6be53a73977f 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2012 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
 #
 # This file is part of pygrader.
 #
@@ -29,9 +29,6 @@ import pgp_mime as _pgp_mime
 
 from . import ENCODING as _ENCODING
 from . import LOG as _LOG
-from .color import standard_colors as _standard_colors
-from .color import color_string as _color_string
-from .color import write_color as _write_color
 from .model.person import Person as _Person
 
 
@@ -49,8 +46,7 @@ def test_smtp(smtp, author, targets, msg=None):
     smtp.send_message(msg=msg)
 test_smtp.__test__ = False  # not a test for nose
 
-def send_emails(emails, smtp=None, use_color=None, debug_target=None,
-                dry_run=False):
+def send_emails(emails, smtp=None, debug_target=None, dry_run=False):
     """Iterate through `emails` and mail them off one-by-one
 
     >>> from email.mime.text import MIMEText
@@ -64,15 +60,12 @@ def send_emails(emails, smtp=None, use_color=None, debug_target=None,
     ...     emails.append(
     ...         (msg,
     ...          lambda status: stdout.write('SUCCESS: {}\\n'.format(status))))
-    >>> send_emails(emails, use_color=False, dry_run=True)
+    >>> send_emails(emails, dry_run=True)
     ... # doctest: +REPORT_UDIFF, +NORMALIZE_WHITESPACE
-    sending message to ['Moneypenny <mp@sis.gov.uk>', 'James Bond <007@sis.gov.uk>']...\tDRY-RUN
     SUCCESS: None
-    sending message to ['M <m@sis.gov.uk>', 'James Bond <007@sis.gov.uk>']...\tDRY-RUN
     SUCCESS: None
     """
     local_smtp = smtp is None
-    highlight,lowlight,good,bad = _standard_colors(use_color=use_color)
     for msg,callback in emails:
         sources = [
             _email_utils.formataddr(a) for a in _pgp_mime.email_sources(msg)]
@@ -84,10 +77,8 @@ def send_emails(emails, smtp=None, use_color=None, debug_target=None,
             # TODO: remove convert_content_transfer_encoding?
             #if msg.get('content-transfer-encoding', None) == 'base64':
             #    convert_content_transfer_encoding(msg, '8bit')
-            _LOG.debug(_color_string(
-                    '\n{}\n'.format(msg.as_string()), color=lowlight))
-        _write_color('sending message to {}...'.format(targets),
-                     color=highlight)
+            _LOG.debug('\n{}\n'.format(msg.as_string()))
+        _LOG.info('sending message to {}...'.format(targets))
         if not dry_run:
             try:
                 if local_smtp:
@@ -98,16 +89,16 @@ def send_emails(emails, smtp=None, use_color=None, debug_target=None,
                 if local_smtp:
                     smtp.quit()
             except:
-                _write_color('\tFAILED\n', bad)
+                _LOG.warning('failed to send message to {}'.format(targets))
                 if callback:
                     callback(False)
                 raise
             else:
-                _write_color('\tOK\n', good)
+                _LOG.info('sent message to {}'.format(targets))
                 if callback:
                     callback(True)
         else:
-            _write_color('\tDRY-RUN\n', good)
+            _LOG.info('dry run, so no message sent to {}'.format(targets))
             if callback:
                 callback(None)
 
@@ -123,48 +114,30 @@ class Responder (object):
         send_emails([(message, None)], *self.args, **self.kwargs)
 
 
-def get_address(person, header=False):
+def get_address(person):
     r"""
     >>> from pygrader.model.person import Person as Person
     >>> p = Person(name='Jack', emails=['a@b.net'])
     >>> get_address(p)
     'Jack <a@b.net>'
 
-    Here's a simple unicode example.
+    Here's a simple unicode example.  The name portion of the address
+    is encoded following RFC 2047.
 
     >>> p.name = '✉'
     >>> get_address(p)
-    '✉ <a@b.net>'
-
-    When you encode addresses that you intend to place in an email
-    header, you should set the `header` option to `True`.  This
-    encodes the name portion of the address without encoding the email
-    portion.
-
-    >>> get_address(p, header=True)
     '=?utf-8?b?4pyJ?= <a@b.net>'
 
-    Note that the address is in the clear.  Without the `header`
-    option you'd have to rely on something like:
-
-    >>> from email.header import Header
-    >>> Header(get_address(p), 'utf-8').encode()
-    '=?utf-8?b?4pyJIDxhQGIubmV0Pg==?='
-
-    This can cause trouble when your mailer tries to decode the name
-    following :RFC:`2822`, which limits the locations in which encoded
-    words may appear.
+    Note that the address is in the clear.  Otherwise you can have
+    trouble when your mailer tries to decode the name following
+    :RFC:`2822`, which limits the locations in which encoded words may
+    appear.
     """
-    if header:
-        encoding = _pgp_mime.guess_encoding(person.name)
-        if encoding == 'us-ascii':
-            name = person.name
-        else:
-            name = _Header(person.name, encoding).encode()
-        return _email_utils.formataddr((name, person.emails[0]))
-    return _email_utils.formataddr((person.name, person.emails[0]))
+    encoding = _pgp_mime.guess_encoding(person.name)
+    return _email_utils.formataddr(
+        (person.name, person.emails[0]), charset=encoding)
 
-def _construct_email(author, targets, subject, message, cc=None):
+def construct_email(author, targets, subject, message, cc=None):
     if author.pgp_key:
         signers = [author.pgp_key]
     else:
@@ -195,13 +168,13 @@ def _construct_email(author, targets, subject, message, cc=None):
         message = _pgp_mime.encrypt(message=message, recipients=recipients)
 
     message['Date'] = _email_utils.formatdate()
-    message['From'] = get_address(author, header=True)
+    message['From'] = get_address(author)
     message['Reply-to'] = message['From']
     message['To'] = ', '.join(
-        get_address(target, header=True) for target in targets)
+        get_address(target) for target in targets)
     if cc:
         message['Cc'] = ', '.join(
-            get_address(target, header=True) for target in cc)
+            get_address(target) for target in cc)
     subject_encoding = _pgp_mime.guess_encoding(subject)
     if subject_encoding == 'us-ascii':
         message['Subject'] = subject
@@ -210,14 +183,14 @@ def _construct_email(author, targets, subject, message, cc=None):
 
     return message
 
-def construct_email(author, targets, subject, text, cc=None):
+def construct_text_email(author, targets, subject, text, cc=None):
     r"""Build a text/plain email using `Person` instances
 
     >>> from pygrader.model.person import Person as Person
     >>> author = Person(name='Джон Доу', emails=['jdoe@a.gov.ru'])
     >>> targets = [Person(name='Jill', emails=['c@d.net'])]
     >>> cc = [Person(name='H.D.', emails=['hd@wall.net'])]
-    >>> msg = construct_email(author, targets, cc=cc,
+    >>> msg = construct_text_email(author, targets, cc=cc,
     ...     subject='Once upon a time', text='Bla bla bla...')
     >>> print(msg.as_string())  # doctest: +REPORT_UDIFF, +ELLIPSIS
     Content-Type: text/plain; charset="us-ascii"
@@ -235,7 +208,7 @@ def construct_email(author, targets, subject, text, cc=None):
 
     With unicode text:
 
-    >>> msg = construct_email(author, targets, cc=cc,
+    >>> msg = construct_text_email(author, targets, cc=cc,
     ...     subject='Once upon a time', text='Funky ✉.')
     >>> print(msg.as_string())  # doctest: +REPORT_UDIFF, +ELLIPSIS
     Content-Type: text/plain; charset="utf-8"
@@ -253,7 +226,7 @@ def construct_email(author, targets, subject, text, cc=None):
     <BLANKLINE>
     """
     message = _pgp_mime.encodedMIMEText(text)
-    return _construct_email(
+    return construct_email(
         author=author, targets=targets, subject=subject, message=message,
         cc=cc)
 
@@ -264,7 +237,7 @@ def construct_response(author, targets, subject, text, original, cc=None):
     >>> student = Person(name='Джон Доу', emails=['jdoe@a.gov.ru'])
     >>> assistant = Person(name='Jill', emails=['c@d.net'])
     >>> cc = [assistant]
-    >>> msg = construct_email(author=student, targets=[assistant],
+    >>> msg = construct_text_email(author=student, targets=[assistant],
     ...     subject='Assignment 1 submission', text='Bla bla bla...')
     >>> rsp = construct_response(author=assistant, targets=[student],
     ...     subject='Received assignment 1 submission', text='3 hours late',
@@ -305,6 +278,6 @@ def construct_response(author, targets, subject, text, original, cc=None):
     message = _MIMEMultipart('mixed')
     message.attach(_pgp_mime.encodedMIMEText(text))
     message.attach(_MIMEMessage(original))
-    return _construct_email(
+    return construct_email(
         author=author, targets=targets, subject=subject, message=message,
         cc=cc)