misc: use django templates to generate emails (#18065)

This commit is contained in:
Frédéric Péters 2017-08-19 13:08:49 +02:00
parent f1d2f0753e
commit 517266fe6d
4 changed files with 90 additions and 40 deletions

View File

@ -298,7 +298,17 @@ def test_email_signature_rst(emails):
assert emails.emails['test']['msg'].get_payload()[0].get_content_type() == 'text/plain'
assert emails.emails['test']['msg'].get_payload()[1].get_content_type() == 'text/html'
assert 'Footer\nText' in emails.emails['test']['msg'].get_payload()[0].get_payload()
assert '>Footer</div>' in emails.emails['test']['msg'].get_payload()[1].get_payload()
assert '>Footer<' in emails.emails['test']['msg'].get_payload()[1].get_payload()
@pytest.mark.skipif('docutils is None')
def test_email_signature_rst_pipes(emails):
pub = create_temporary_pub()
pub.cfg['emails'] = {'footer': '| Footer\n| Text'}
send_email('test', mail_body='Hello', email_rcpt='test@localhost')
assert emails.emails['test']['msg'].get_payload()[0].get_content_type() == 'text/plain'
assert emails.emails['test']['msg'].get_payload()[1].get_content_type() == 'text/html'
assert 'Footer\nText' in emails.emails['test']['msg'].get_payload()[0].get_payload()
assert '>Footer<' in emails.emails['test']['msg'].get_payload()[1].get_payload()
def test_cache():
cache.set('hello', 'world')

View File

@ -15,6 +15,7 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import os
import re
from email.mime.application import MIMEApplication
from email.MIMEText import MIMEText
@ -34,6 +35,10 @@ try:
except ImportError:
docutils = None
from django.template import Context
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from quixote import get_request, get_response, get_publisher
from publisher import get_cfg, get_logger
@ -104,27 +109,27 @@ def email(subject, mail_body, email_rcpt, replyto = None, bcc = None,
fire_and_forget = False
emails_cfg = get_cfg('emails', {})
footer = emails_cfg.get('footer')
footer = emails_cfg.get('footer') or ''
encoding = get_publisher().site_charset
mail_body = str(mail_body)
htmlmail = None
if want_html:
# in restructuredtext lines starting with a pipe were used to give
# appropriate multiline formatting, remove them.
footer = re.sub(r'^\|\s+', '', footer, flags=re.DOTALL | re.MULTILINE)
text_body = str(mail_body)
html_body = None
if text_body.startswith('<'):
# native HTML, keep it that way
html_body = text_body
text_body = None
elif want_html:
# body may be reStructuredText, try converting.
try:
if footer:
rst_footer = footer
if not rst_footer.startswith('|') and '\n' in rst_footer:
# unless the footer text is already formatted like a block
# of lines, add pipes to give it appropriate multilines
# formatting.
rst_footer = '\n'.join(['| ' + x for x in rst_footer.splitlines()])
rst_mail_body = mail_body + '\n\n--------\n\n' + rst_footer
else:
rst_mail_body = mail_body
htmlmail, pub = docutils.core.publish_programmatically(
source_class = docutils.io.StringInput,
source = rst_mail_body,
source = mail_body,
source_path = None,
destination_class = docutils.io.StringOutput,
destination = None,
@ -144,28 +149,41 @@ def email(subject, mail_body, email_rcpt, replyto = None, bcc = None,
config_section = None,
enable_exit_status = None)
except:
htmlmail = None
try:
html_body = re.findall('<body>(.*)</body>', htmlmail or '', re.DOTALL)[0]
except IndexError:
pass
else:
if pub.document.reporter.max_level >= 3:
# notify user
pass
if mail_body.startswith('<'):
htmlmail = mail_body
mail_body = None
elif footer:
mail_body += '\n-- \n' + footer
context = Context(get_publisher().get_substitution_variables())
context['email_signature'] = footer
# If the mail contains only one part, make it the main contentn of the mail
if text_body:
context['content'] = mark_safe(text_body)
text_body = render_to_string('qommon/email_body.txt', context)
if html_body:
context['content'] = mark_safe(html_body)
html_body = render_to_string('qommon/email_body.html', context)
# If the mail contains only one part, make it the main content of the mail
# and do not use the multipart encoding
multipart = (len(attachments) > 0) or (mail_body and htmlmail)
multipart = (len(attachments) > 0) or (text_body and html_body)
if multipart:
msg = MIMEMultipart(_charset = encoding, _subtype = 'alternative')
msg = MIMEMultipart(_charset=encoding, _subtype='alternative')
msg.preamble = ''
msg.epilogue = ''
if text_body:
msg.attach(MIMEText(text_body, _charset=encoding))
if html_body:
msg.attach(MIMEText(html_body, _subtype='html', _charset=encoding))
else:
if mail_body:
msg = MIMEText(mail_body, _charset = encoding)
if text_body:
msg = MIMEText(text_body, _charset=encoding)
else:
msg = MIMEText(htmlmail, _subtype = 'html', _charset = encoding)
msg = MIMEText(html_body, _subtype='html', _charset=encoding)
msg['Subject'] = Header(subject, encoding)
if hide_recipients or email_rcpt is None:
@ -186,15 +204,6 @@ def email(subject, mail_body, email_rcpt, replyto = None, bcc = None,
msg['X-Qommon-Id'] = os.path.basename(get_publisher().app_dir)
msg.preamble = ''
msg.epilogue = ''
if mail_body and multipart:
msg.attach(MIMEText(mail_body, _charset = encoding))
if htmlmail and multipart:
msg.attach(MIMEText(htmlmail, _subtype = 'html', _charset = encoding))
for attachment in attachments:
msg.attach(attachment)

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
</head>
<body>
<div style="max-width: 60ex;">
<div class="content">
{% block content %}
{{ content }}
{% endblock %}
</div>
{% block footer %}
{% if email_signature %}
<div style="font-size: smaller; font-color: #888; margin-top: 2em;">
{{ email_signature|linebreaks }}
</div>
{% endif %}
{% endblock %}
</div>
</body>
</html>

View File

@ -0,0 +1,9 @@
{% block content %}
{{ global_title }}
{{ content }}
{% endblock %}
{% block footer %}
{% if email_signature %}--
{{ email_signature|safe }}{% endif %}
{% endblock %}