# Copyright (c) 2005-2006 Simplistix Ltd # # This Software is released under the MIT License: # http://www.opensource.org/licenses/mit-license.html # See license.txt for more details. import os import rfc822 from AccessControl import ClassSecurityInfo from DateTime import DateTime from email.Header import Header from email.MIMEMultipart import MIMEMultipart from email.MIMEText import MIMEText from email.Utils import make_msgid, formataddr, getaddresses from App.class_init import default__class_init__ as InitializeClass from App.Common import package_home from MTMultipart import MTMultipart from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate from Products.PageTemplates.PageTemplateFile import PageTemplateFile from ZPublisher import HTTPResponse # Configured using zope.conf in Zope 2.7.8, Zope 2.8.2, and above default_encoding = getattr(HTTPResponse,'default_encoding','iso-8859-15') class BaseMailTemplate: security = ClassSecurityInfo() _properties = () ZScriptHTML_tryForm = None content_type = 'text/plain' mailhost = None security.declarePrivate('_process') def _process(self,kw): # sort out what encoding we're going to use encoding = kw.get('encoding', self.getProperty('encoding', default_encoding)) text = self.__class__.__bases__[1].__call__(self,**kw) # ZPT adds newline at the end, but it breaks backward compatibility. # So I remove it. if text.endswith('\n'): text = text[:-1] if not self.html() and isinstance(text, unicode): text = text.encode(encoding,'replace') # now turn the result into a MIMEText object msg = MIMEText( text.replace('\r',''), self.content_type.split('/')[1], encoding ) # sort out what headers and addresses we're going to use headers = {} values = {} # headers from the headers property for header in getattr(self,'headers',()): name,value = header.split(':',1) headers[name]=value # headers from the headers parameter headers_param = kw.get('headers',{}) headers.update(headers_param) # values and some specific headers for key,header in (('mfrom','From'), ('mto','To'), ('mcc','Cc'), ('mbcc','Bcc'), ('subject','Subject')): value = kw.get(key, headers_param.get(header, getattr(self, key, headers.get(header)))) if value is not None: values[key]=value if key == 'subject': try: # Try to keep header non encoded value = Header(value) except UnicodeDecodeError: value = Header(value, "UTF-8") else: dest_list = [] for name, email in getaddresses((value,) if isinstance(value, basestring) else value): try: name = Header(name) except UnicodeDecodeError: name = Header(name, "UTF-8") dest_list.append(formataddr((name.encode(), email))) value = ", ".join(dest_list) headers[header]=value # check required values have been supplied errors = [] for param in ('mfrom','mto'): if not values.get(param): errors.append(param) if errors: raise TypeError( 'The following parameters were required by not specified: '+( ', '.join(errors) )) # add date header headers['Date']=DateTime().rfc822() # do not let the MTA to generate the Message-ID: # we want to have it stored in ERP5, for mail threading headers['Message-ID'] = make_msgid() # turn headers into an ordered list for predictable header order keys = headers.keys() keys.sort() return msg,values,[(key,headers[key]) for key in keys] security.declarePrivate('_send') def _send(self,mfrom,mto,msg): mailhost = self.restrictedTraverse(self.mailhost,None) if not getattr(mailhost,'meta_type',None) in ( 'Mail Host','Maildrop Host' ): raise RuntimeError( 'Could not traverse to MailHost %r' % self.mailhost ) mailhost._send(mfrom,mto,msg.as_string()) security.declareProtected('View', 'send') def send(self,**kw): msg,values,headers = self._process(kw) for header,value in headers: msg[header]=value to_addrs = () for key in ('mto', 'mcc', 'mbcc'): v = values.get(key) if v: if isinstance(v, basestring): v = [rfc822.dump_address_pair(addr) for addr \ in rfc822.AddressList(v)] to_addrs += tuple(v) self._send(values['mfrom'], to_addrs, msg) security.declareProtected('View', '__call__') __call__ = send security.declareProtected('View', 'as_message') def as_message(self,**kw): msg,values,headers = self._process(kw) multipart_kw = {} #subtype = kw.get('subtype') #if subtype: # multipart_kw['_subtype'] = subtype #boundary = kw.get('boundary') #if boundary: # multipart_kw['boundary'] = boundary multipart = MTMultipart(self, values['mfrom'], values['mto'], **multipart_kw) # set the encoding for the container #multipart.set_charset(msg.get_charset()) for header,value in headers: multipart[header]=value multipart.attach(msg) return multipart InitializeClass(BaseMailTemplate)