This is a snapshot of Indico's old Trac site. Any information contained herein is most probably outdated. Access our new GitHub site here.

Ticket #1090: 0001-FEATURE-Use-the-python-email-module.patch

File 0001-FEATURE-Use-the-python-email-module.patch, 7.9 KB (added by pedersen, 2 years ago)

based on current master

  • indico/MaKaC/common/mail.py

    From 441ad80ed4d0786622a44a9fcb33a2c415fb2345 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Bj=C3=B6rn=20Pedersen?= <bjoern.pedersen@frm2.tum.de>
    Date: Wed, 19 Sep 2012 10:48:50 +0200
    Subject: [PATCH 1/4] [FEATURE] Use the python email module
    
    Use the python email module to generate emails not only as
    plain text, but as MIME with attachments and HTML as well.
    
    Attachment definition is still a bit rough, but currently for non-text
    types a file path has to be used.
    ---
     indico/MaKaC/common/mail.py                        | 93 ++++++++++++++++++++--
     .../MaKaC/webinterface/common/baseNotificator.py   |  3 +
     indico/MaKaC/webinterface/mail.py                  | 35 ++++++--
     3 files changed, 119 insertions(+), 12 deletions(-)
    
    diff --git a/indico/MaKaC/common/mail.py b/indico/MaKaC/common/mail.py
    index bf64cde..ffe0f13 100644
    a b  
    1919 
    2020import smtplib 
    2121from email.utils import formatdate 
     22from email import encoders 
     23from email.message import Message 
     24from email.mime.audio import MIMEAudio 
     25from email.mime.base import MIMEBase 
     26from email.mime.image import MIMEImage 
     27from email.mime.multipart import MIMEMultipart 
     28from email.mime.text import MIMEText 
     29from email.header import Header 
     30from email.charset import add_charset 
     31from email import Charset 
     32# don#t encode utf-8 as base64, use quoted-printable! 
     33# as this sets a module global, needs to be done only once 
     34add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8') 
     35 
     36 
    2237 
    2338from MaKaC.common import Config 
    2439from MaKaC.errors import MaKaCError 
    class GenericMailer: 
    5974 
    6075    @staticmethod 
    6176    def _prepare(notification): 
     77        COMMASPACE = " ," 
    6278        fromAddr=notification.getFromAddr() 
    6379        # what are these two loops for?? 
    6480        for to in notification.getToList() : 
    class GenericMailer: 
    6884            if len(cc) == 0 : 
    6985                notification.getCCList().remove(cc) 
    7086 
    71         to=", ".join(notification.getToList()) 
    72         cc="" 
     87        to = COMMASPACE.join(notification.getToList()) 
     88        cc = "" 
    7389        if len(notification.getCCList())>0: 
    74             cc="Cc: %s\r\n"%", ".join(notification.getCCList()) 
     90            cc = COMMASPACE.join(notification.getCCList()) 
    7591        if not to and not cc: 
    7692            return 
    7793 
    class GenericMailer: 
    8197            ct = "text/plain" 
    8298        subject=notification.getSubject() 
    8399        body=notification.getBody() 
    84         msg="""Content-Type: %s; charset=\"utf-8\"\r\nFrom: %s\r\nTo: %s\r\n%sSubject: %s\r\nDate: %s\r\n\r\n%s"""%(ct, fromAddr,\ 
    85                 to,cc,subject,formatdate(localtime=True),body) 
     100        try: 
     101            bodyHTML=notification.getBodyHTML() 
     102        except AttributeError: 
     103            bodyHTML = None 
     104        try: 
     105            attachments = notification.getAttachments() 
     106        except AttributeError: 
     107            attachments = None 
     108 
     109 
     110        target = None 
     111        if attachments: 
     112            outer = MIMEMultipart() 
     113        elif bodyHTML: 
     114            outer = MIMEMultipart('alternative') 
     115            target = outer 
     116        else: 
     117            outer = MIMEText(body, 'plain','utf-8') 
     118            target = outer 
     119 
     120        if bodyHTML: 
     121            msg = target or MIMEMultipart('alternative') 
     122            part1HTML = MIMEText(bodyHTML, 'html','utf-8') 
     123            part1Plain = MIMEText(body, 'plain', 'utf-8') 
     124            # Attach parts into message container. 
     125            # According to RFC 2046, the last part of a multipart message, in this case 
     126            # the HTML message, is best and preferred. 
     127            msg.attach(part1Plain) 
     128            msg.attach(part1HTML) 
     129        else: 
     130            msg = target or MIMEText(body, 'plain','utf-8') 
     131 
     132        outer['Subject'] = Header(subject,'utf-8') 
     133        outer['To'] = to 
     134        outer['CC'] = cc 
     135        outer['From'] = fromAddr 
     136 
     137        if outer != msg: 
     138            outer.attach(msg) 
     139 
     140        #add iteration over attachments 
     141        #for text type, the content should be the payload string, 
     142        #for all other types the content should be the path to a (possibly temporary) file 
     143        if attachments: 
     144            for ctype, vpath, content in attachments: 
     145 
     146                maintype, subtype = ctype.split('/', 1) 
     147            if maintype == 'text': 
     148                # Note: we should handle calculating the charset 
     149                msg = MIMEText(content , _subtype=subtype) 
     150            elif maintype == 'image': 
     151                with open(content, 'rb') as fp: 
     152                    msg = MIMEImage(fp.read(), _subtype=subtype) 
     153            elif maintype == 'audio': 
     154                with open(content, 'rb') as fp: 
     155                    msg = MIMEAudio(fp.read(), _subtype=subtype) 
     156            else: 
     157                with open(content, 'rb') as fp: 
     158                    msg = MIMEBase(maintype, subtype) 
     159                    msg.set_payload(fp.read()) 
     160                    # Encode the payload using Base64 
     161                    encoders.encode_base64(msg) 
     162            # Set the filename parameter 
     163            msg.add_header('Content-Disposition', 'attachment', filename=vpath) 
     164            outer.attach(msg) 
     165 
     166 
    86167        toList = notification.getToList() 
    87168        ccList = notification.getCCList() 
    88169        if hasattr(notification, 'getBCCList'): 
    class GenericMailer: 
    90171        else: 
    91172            bccList = [] 
    92173        return { 
    93             'msg': msg, 
     174            'msg': outer.as_string(True), 
    94175            'toList': toList, 
    95176            'ccList': ccList, 
    96177            'bccList': bccList, 
  • indico/MaKaC/webinterface/common/baseNotificator.py

    diff --git a/indico/MaKaC/webinterface/common/baseNotificator.py b/indico/MaKaC/webinterface/common/baseNotificator.py
    index ba574c1..4926fff 100644
    a b class Notification: 
    5858    def getBody(self): 
    5959        return self._body 
    6060 
     61    def getBodyHTML(self): 
     62        return None 
     63 
    6164    def setToList(self,newList): 
    6265        self._toList=[] 
    6366        for to in newList: 
  • indico/MaKaC/webinterface/mail.py

    diff --git a/indico/MaKaC/webinterface/mail.py b/indico/MaKaC/webinterface/mail.py
    index 06c026c..f78fedb 100644
    a b class GenericNotification : 
    6060            self._bccList = [] 
    6161            self._subject = "" 
    6262            self._body = "" 
     63            self.bodyHTML = "" 
    6364            self._contenttype = "text/plain" 
     65            self._attachments = [] 
    6466        else : 
    65             self._fromAddr = data.get("fromAddr", "") 
    66             self._toList = data.get("toList", []) 
    67             self._ccList = data.get("ccList", []) 
     67            self._fromAddr = data.get("fromAddr","") 
     68            self._toList = data.get("toList",[]) 
     69            self._ccList = data.get("ccList",[]) 
    6870            self._bccList = data.get("bccList", []) 
    69             self._subject = data.get("subject", "") 
    70             self._body = data.get("body", "") 
    71             self._contenttype = data.get("content-type", "text/plain") 
     71            self._subject = data.get("subject","") 
     72            self._body = data.get("body","") 
     73            self._bodyHTML = data.get("bodyHTML","") 
     74            self._attachments = data.get("attachments",[]) 
     75            defaultContentType = "text/html" if self._bodyHTML else "text/plain" 
     76            self._contenttype = data.get("content-type",defaultContentType) 
    7277 
    7378    def getContentType(self): 
    7479        return self._contenttype 
    class GenericNotification : 
    130135        self._body = body 
    131136        return True 
    132137 
     138    def getBodyHTML(self): 
     139        return self._bodyHTML 
     140 
     141    def setBodyHTML(self, bodyHTML): 
     142        if bodyHTML is None : 
     143            return False 
     144        self._bodyHTML = bodyHTML 
     145        return True 
     146 
     147    def getAttachments(self): 
     148        return self._bodyHTML 
     149 
     150    def setAttachments(self, attachments): 
     151        if attachments is None : 
     152            return False 
     153        self._attachments = attachments 
     154        return True 
     155 
    133156 
    134157class Mailer: 
    135158