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':
mail_template = context.Event_viewHtmlMimeMessage
else:
......@@ -20,7 +40,8 @@ multipart = mail_template.as_message(mfrom=from_url,
mto=to_url,
subject=subject,
body=body,
encoding='utf-8')
encoding='utf-8',
headers=extra_header_dict)
for attachment_dict in attachment_list:
multipart.add_file(data=attachment_dict['content'],
content_type=attachment_dict['mime_type'],
......
......@@ -50,7 +50,7 @@
</item>
<item>
<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>
<key> <string>id</string> </key>
......
......@@ -17,12 +17,16 @@ to_url = formataddr((context.hasTitle() and context.getTitle(), context.getDefau
document_type_list = list(event.getPortalEmbeddedDocumentTypeList()) + list(event.getPortalDocumentTypeList())
embedded_file_list = event.getAggregateValueList(portal_type=document_type_list)
extra_header_dict = kw.get('extra_header_dict') or {}
content_type = event.getContentType()
mail_message = portal.Base_createMailMessageAsString(from_url,
mail_message = portal.Base_createMailMessageAsString(
from_url,
to_url,
subject,
body,
content_type,
embedded_file_list=embedded_file_list)
embedded_file_list=embedded_file_list,
extra_header_dict=extra_header_dict)
event.sendMailHostMessage(mail_message)
......@@ -70,12 +70,14 @@ if download or not use_activity:
content_type = context.getContentType()
mail_message = context.Base_createMailMessageAsString(from_url,
mail_message = context.Base_createMailMessageAsString(
from_url,
to_url,
subject,
body,
content_type,
embedded_file_list=embedded_file_list)
embedded_file_list=embedded_file_list,
extra_header_dict=extra_header_dict)
if not use_activity:
context.activate(activity='SQLQueue').sendMailHostMessage(mail_message)
......@@ -83,6 +85,8 @@ if download or not use_activity:
if use_activity:
method_kw = dict(event_relative_url=context.getRelativeUrl(),
from_url=from_url)
if extra_header_dict:
method_kw['extra_header_dict'] = extra_header_dict
context.activate(
after_path_and_method_id=((context.getPath(),),
('immediateReindexObject', 'recursiveImmediateReindexObject'))).MailMessage_sendByActivity(
......
......@@ -50,7 +50,7 @@
</item>
<item>
<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>
<key> <string>_proxy_roles</string> </key>
......
......@@ -40,6 +40,7 @@ from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.audio import MIMEAudio
from email.mime.image import MIMEImage
from email.utils import formataddr
from email.header import make_header
from email import encoders
......@@ -333,8 +334,7 @@ class NotificationTool(BaseTool):
default_from_name = getattr(portal, 'email_from_name', default_from_name)
if from_person is None:
# when sending without sender defined compose identifiable From header
low_level_kw['from_url'] = '%s <%s>' % (default_from_name,
default_from_email)
low_level_kw['from_url'] = formataddr((default_from_name, default_from_email))
if not to_person_list:
low_level_kw['to_url'] = default_to_email
if attachment_list is not None:
......
......@@ -1852,6 +1852,20 @@ class TestCRMMailSend(BaseTestCRM):
self.assertEqual('FG ER <eee@eee.com>', from_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():
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