from __future__ import absolute_import # 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. from six import string_types as basestring import os import six from AccessControl import ClassSecurityInfo from DateTime import DateTime from email.header import Header from six.moves.email_mime_multipart import MIMEMultipart from six.moves.email_mime_text import MIMEText from email.utils import make_msgid, formataddr, getaddresses from AccessControl.class_init import InitializeClass from App.Common import package_home from .MTMultipart import MTMultipart from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate from Products.PageTemplates.PageTemplateFile import PageTemplateFile from Products.ERP5Type.Utils import ensure_list 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 six.PY2 and not self.html() and isinstance(text, six.text_type): 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 return msg, values, [(key, value) for key, value in sorted(six.iteritems(headers))] 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 = [formataddr(addr) for addr in getaddresses([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)