Commit cb9d0c70 authored by Jérome Perrin's avatar Jérome Perrin

Support arbitrary email headers

As discussed in  nexedi/erp5!248 this approach allows to set any mail header.

I also included a not so related patch of email header handlings 88d40b40 so that we review all this together.

/cc @gabriel @kazuhiko 

/reviewed-on nexedi/erp5!256
parents 8a27134c d382489f
"""Build a mail message
* from_url: the "from" address as UTF-8 encoded string
* to_url: the "to" header as UTF-8 encoded string
* subject: the subject of the message as UTF-8 encoded string
* body: body of the message as UTF-8 encoded string
* content_type: mime type of this message, can be text/html for
HTML message or anything else for text/plain message.
* attachment_list: a list of attachement mapping in format:
- mime_type: mime type of thsi attachement
- content: file content of the attachement, as a string
- name: displayed name of this attachements
* embedded_file_list: a list of ERP5 File to use as attachments.
* extra_header_dict: additional email headers
Notes: for from_url and to_url, we should use email.utils.formataddr
"""
if extra_header_dict is None:
extra_header_dict = {}
if content_type == 'text/html': if content_type == 'text/html':
mail_template = context.Event_viewHtmlMimeMessage mail_template = context.Event_viewHtmlMimeMessage
else: else:
...@@ -20,7 +40,8 @@ multipart = mail_template.as_message(mfrom=from_url, ...@@ -20,7 +40,8 @@ multipart = mail_template.as_message(mfrom=from_url,
mto=to_url, mto=to_url,
subject=subject, subject=subject,
body=body, body=body,
encoding='utf-8') encoding='utf-8',
headers=extra_header_dict)
for attachment_dict in attachment_list: for attachment_dict in attachment_list:
multipart.add_file(data=attachment_dict['content'], multipart.add_file(data=attachment_dict['content'],
content_type=attachment_dict['mime_type'], content_type=attachment_dict['mime_type'],
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>from_url, to_url, subject, body, content_type, attachment_list=[], embedded_file_list=[]</string> </value> <value> <string>from_url, to_url, subject, body, content_type, attachment_list=[], embedded_file_list=[], extra_header_dict=None</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -17,12 +17,16 @@ to_url = formataddr((context.hasTitle() and context.getTitle(), context.getDefau ...@@ -17,12 +17,16 @@ to_url = formataddr((context.hasTitle() and context.getTitle(), context.getDefau
document_type_list = list(event.getPortalEmbeddedDocumentTypeList()) + list(event.getPortalDocumentTypeList()) document_type_list = list(event.getPortalEmbeddedDocumentTypeList()) + list(event.getPortalDocumentTypeList())
embedded_file_list = event.getAggregateValueList(portal_type=document_type_list) embedded_file_list = event.getAggregateValueList(portal_type=document_type_list)
extra_header_dict = kw.get('extra_header_dict') or {}
content_type = event.getContentType() content_type = event.getContentType()
mail_message = portal.Base_createMailMessageAsString(from_url, mail_message = portal.Base_createMailMessageAsString(
from_url,
to_url, to_url,
subject, subject,
body, body,
content_type, content_type,
embedded_file_list=embedded_file_list) embedded_file_list=embedded_file_list,
extra_header_dict=extra_header_dict)
event.sendMailHostMessage(mail_message) event.sendMailHostMessage(mail_message)
...@@ -70,12 +70,14 @@ if download or not use_activity: ...@@ -70,12 +70,14 @@ if download or not use_activity:
content_type = context.getContentType() content_type = context.getContentType()
mail_message = context.Base_createMailMessageAsString(from_url, mail_message = context.Base_createMailMessageAsString(
from_url,
to_url, to_url,
subject, subject,
body, body,
content_type, content_type,
embedded_file_list=embedded_file_list) embedded_file_list=embedded_file_list,
extra_header_dict=extra_header_dict)
if not use_activity: if not use_activity:
context.activate(activity='SQLQueue').sendMailHostMessage(mail_message) context.activate(activity='SQLQueue').sendMailHostMessage(mail_message)
...@@ -83,6 +85,8 @@ if download or not use_activity: ...@@ -83,6 +85,8 @@ if download or not use_activity:
if use_activity: if use_activity:
method_kw = dict(event_relative_url=context.getRelativeUrl(), method_kw = dict(event_relative_url=context.getRelativeUrl(),
from_url=from_url) from_url=from_url)
if extra_header_dict:
method_kw['extra_header_dict'] = extra_header_dict
context.activate( context.activate(
after_path_and_method_id=((context.getPath(),), after_path_and_method_id=((context.getPath(),),
('immediateReindexObject', 'recursiveImmediateReindexObject'))).MailMessage_sendByActivity( ('immediateReindexObject', 'recursiveImmediateReindexObject'))).MailMessage_sendByActivity(
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>from_url=None, to_url=None, reply_url=None, subject=None, body=None, attachment_format=None, attachment_list=None, download=None, **kw</string> </value> <value> <string>from_url=None, to_url=None, reply_url=None, subject=None, body=None, attachment_format=None, attachment_list=None, download=None, extra_header_dict=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
...@@ -40,6 +40,7 @@ from email.mime.text import MIMEText ...@@ -40,6 +40,7 @@ from email.mime.text import MIMEText
from email.mime.base import MIMEBase from email.mime.base import MIMEBase
from email.mime.audio import MIMEAudio from email.mime.audio import MIMEAudio
from email.mime.image import MIMEImage from email.mime.image import MIMEImage
from email.utils import formataddr
from email.header import make_header from email.header import make_header
from email import encoders from email import encoders
...@@ -333,8 +334,7 @@ class NotificationTool(BaseTool): ...@@ -333,8 +334,7 @@ class NotificationTool(BaseTool):
default_from_name = getattr(portal, 'email_from_name', default_from_name) default_from_name = getattr(portal, 'email_from_name', default_from_name)
if from_person is None: if from_person is None:
# when sending without sender defined compose identifiable From header # when sending without sender defined compose identifiable From header
low_level_kw['from_url'] = '%s <%s>' % (default_from_name, low_level_kw['from_url'] = formataddr((default_from_name, default_from_email))
default_from_email)
if not to_person_list: if not to_person_list:
low_level_kw['to_url'] = default_to_email low_level_kw['to_url'] = default_to_email
if attachment_list is not None: if attachment_list is not None:
......
...@@ -1852,6 +1852,20 @@ class TestCRMMailSend(BaseTestCRM): ...@@ -1852,6 +1852,20 @@ class TestCRMMailSend(BaseTestCRM):
self.assertEqual('FG ER <eee@eee.com>', from_url) self.assertEqual('FG ER <eee@eee.com>', from_url)
self.assertEqual(['Expert User <expert@in24.test>'], to_url) self.assertEqual(['Expert User <expert@in24.test>'], to_url)
def test_MailMessage_send_extra_headers(self):
"""Test sending message with extra headers
"""
mail_message = self.portal.event_module.newContent(
portal_type="Mail Message",
source='person_module/me',
destination='person_module/recipient')
mail_message.send(extra_header_dict={"X-test-header": "test"})
self.tic()
(from_url, to_url, last_message,), = self.portal.MailHost._message_list
message = message_from_string(last_message)
self.assertEqual("test", message.get("X-test-header"))
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment