commit 35079ab2f2b4c3f4b88f41d44d6b92bbb18bad09
Author: Georgios Gousios <gousiosg@gmail.com>
Date:   Thu May 26 17:55:34 2011 +0300

    Better handling of Unicode emails, catch SMTP connection errors

diff --git a/logic/dispatcher_callbacks.py b/logic/dispatcher_callbacks.py
index 048f8e6..2c62af2 100644
--- a/logic/dispatcher_callbacks.py
+++ b/logic/dispatcher_callbacks.py
@@ -4,6 +4,7 @@
 #
 # Copyright 2010 Greek Research and Technology Network
 #
+import socket
 import traceback
 import json
 import logging
@@ -83,16 +84,17 @@ def send_email(message):
     try:
         msg = json.loads(message.body)
 
-        email_send.send(frm=msg['frm'], to = msg['to'],
+        email_send.send(sender=msg['frm'], recipient = msg['to'],
                         body=msg['body'], subject=msg['subject'])
         message.channel.basic_ack(message.delivery_tag)
     except KeyError:
         _logger.error("Malformed incoming JSON, missing attributes: %s",
                       message.body)
+    except socket.error as e:
+        _logger.error("Cannot connect to SMTP server:%s\n", e)
     except Exception as e:
-        _logger.error("Unexpected error:%s\n%s",
-                      (e.message,"".
-                      join(traceback.format_exception(*sys.exc_info()))))
+        _logger.error("Unexpected error:%s\n", e)
+        raise
 
 
 def update_credits(message):
diff --git a/logic/email_send.py b/logic/email_send.py
index b104550..246b5a5 100644
--- a/logic/email_send.py
+++ b/logic/email_send.py
@@ -1,6 +1,9 @@
 import json
-import smtplib
-from email.mime.text import MIMEText
+
+from smtplib import SMTP
+from email.mime import text
+from email.header import Header
+from email.utils import parseaddr, formataddr
 
 from django.conf import settings
 import amqp_connection
@@ -23,21 +26,56 @@ def send_async(frm = settings.SYSTEM_EMAIL_ADDR,
     amqp_connection.send(json.dumps(msg), settings.EXCHANGE_API, routekey)
 
 
-def send (frm = settings.SYSTEM_EMAIL_ADDR,
-          to = None, subject = None, body = None):
+def send (sender = settings.SYSTEM_EMAIL_ADDR,
+          recipient = None, subject = None, body = None):
     """
         Connect to the email server configured in settings.py
         and send the email.
 
+        All arguments should be Unicode strings (plain ASCII works as well).
+
+        Only the real name part of sender and recipient addresses may contain
+        non-ASCII characters.
+
+        The charset of the email will be the first one out of US-ASCII, ISO-8859-1
+        and UTF-8 that can represent all the characters occurring in the email.
+        
         This method does not perform any error checking and does
         not guarantee delivery
     """
 
-    msg = MIMEText(body, _charset="utf-8")
-    msg['Subject'] = subject
-    msg['From'] = frm
-    msg['To'] = to
+    # Header class is smart enough to try US-ASCII, then the charset we
+    # provide, then fall back to UTF-8.
+    header_charset = 'ISO-8859-7'
+
+    # We must choose the body charset manually
+    for body_charset in 'US-ASCII', 'ISO-8859-7', 'UTF-8':
+        try:
+            body.encode(body_charset)
+        except UnicodeError:
+            pass
+        else:
+            break
+
+    # Split real name (which is optional) and email address parts
+    sender_name, sender_addr = parseaddr(sender)
+    recipient_name, recipient_addr = parseaddr(recipient)
+
+    # We must always pass Unicode strings to Header, otherwise it will
+    # use RFC 2047 encoding even on plain ASCII strings.
+    sender_name = str(Header(unicode(sender_name), header_charset))
+    recipient_name = str(Header(unicode(recipient_name), header_charset))
+
+    # Make sure email addresses do not contain non-ASCII characters
+    sender_addr = sender_addr.encode('ascii')
+    recipient_addr = recipient_addr.encode('ascii')
+
+    # Create the message ('plain' stands for Content-Type: text/plain)
+    msg = text.MIMEText(body.encode(body_charset), 'plain', body_charset)
+    msg['From'] = formataddr((sender_name, sender_addr))
+    msg['To'] = formataddr((recipient_name, recipient_addr))
+    msg['Subject'] = Header(unicode(subject), header_charset)
 
-    s = smtplib.SMTP(host=settings.SMTP_SERVER)
-    s.sendmail(frm, [to], msg.as_string())
+    s = SMTP(host=settings.SMTP_SERVER)
+    s.sendmail(sender, recipient, msg.as_string())
     s.quit()
