2018-10-31 16:24:57 +01:00
|
|
|
|
2020-10-29 23:32:02 +01:00
|
|
|
from django.conf import settings
|
2018-10-31 16:24:57 +01:00
|
|
|
from django.utils.safestring import mark_safe
|
2022-07-22 03:26:41 +02:00
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
from smtplib import SMTPException
|
|
|
|
|
2018-10-31 16:24:57 +01:00
|
|
|
|
|
|
|
logger = logging.getLogger('helpdesk')
|
|
|
|
|
|
|
|
|
|
|
|
def send_templated_mail(template_name,
|
|
|
|
context,
|
|
|
|
recipients,
|
|
|
|
sender=None,
|
|
|
|
bcc=None,
|
|
|
|
fail_silently=False,
|
2018-12-28 16:53:28 +01:00
|
|
|
files=None,
|
2021-04-15 10:39:55 +02:00
|
|
|
extra_headers=None):
|
2018-10-31 16:24:57 +01:00
|
|
|
"""
|
|
|
|
send_templated_mail() is a wrapper around Django's e-mail routines that
|
|
|
|
allows us to easily send multipart (text/plain & text/html) e-mails using
|
|
|
|
templates that are stored in the database. This lets the admin provide
|
|
|
|
both a text and a HTML template for each message.
|
|
|
|
|
|
|
|
template_name is the slug of the template to use for this message (see
|
|
|
|
models.EmailTemplate)
|
|
|
|
|
|
|
|
context is a dictionary to be used when rendering the template
|
|
|
|
|
|
|
|
recipients can be either a string, eg 'a@b.com', or a list of strings.
|
|
|
|
|
|
|
|
sender should contain a string, eg 'My Site <me@z.com>'. If you leave it
|
|
|
|
blank, it'll use settings.DEFAULT_FROM_EMAIL as a fallback.
|
|
|
|
|
|
|
|
bcc is an optional list of addresses that will receive this message as a
|
|
|
|
blind carbon copy.
|
|
|
|
|
|
|
|
fail_silently is passed to Django's mail routine. Set to 'True' to ignore
|
|
|
|
any errors at send time.
|
|
|
|
|
|
|
|
files can be a list of tuples. Each tuple should be a filename to attach,
|
|
|
|
along with the File objects to be read. files can be blank.
|
2018-12-28 17:32:49 +01:00
|
|
|
|
2018-12-28 16:53:28 +01:00
|
|
|
extra_headers is a dictionary of extra email headers, needed to process
|
|
|
|
email replies and keep proper threading.
|
2018-10-31 16:24:57 +01:00
|
|
|
|
|
|
|
"""
|
|
|
|
from django.core.mail import EmailMultiAlternatives
|
|
|
|
from django.template import engines
|
|
|
|
from_string = engines['django'].from_string
|
|
|
|
|
|
|
|
from helpdesk.models import EmailTemplate
|
2022-07-22 03:26:41 +02:00
|
|
|
from helpdesk.settings import HELPDESK_EMAIL_FALLBACK_LOCALE, HELPDESK_EMAIL_SUBJECT_TEMPLATE
|
2018-10-31 16:24:57 +01:00
|
|
|
|
2021-04-15 10:39:55 +02:00
|
|
|
headers = extra_headers or {}
|
|
|
|
|
2018-10-31 16:24:57 +01:00
|
|
|
locale = context['queue'].get('locale') or HELPDESK_EMAIL_FALLBACK_LOCALE
|
|
|
|
|
|
|
|
try:
|
2022-07-12 12:34:19 +02:00
|
|
|
t = EmailTemplate.objects.get(
|
|
|
|
template_name__iexact=template_name, locale=locale)
|
2018-10-31 16:24:57 +01:00
|
|
|
except EmailTemplate.DoesNotExist:
|
|
|
|
try:
|
2022-07-12 12:34:19 +02:00
|
|
|
t = EmailTemplate.objects.get(
|
|
|
|
template_name__iexact=template_name, locale__isnull=True)
|
2018-10-31 16:24:57 +01:00
|
|
|
except EmailTemplate.DoesNotExist:
|
2022-07-12 12:34:19 +02:00
|
|
|
logger.warning(
|
|
|
|
'template "%s" does not exist, no mail sent', template_name)
|
2018-10-31 16:24:57 +01:00
|
|
|
return # just ignore if template doesn't exist
|
|
|
|
|
|
|
|
subject_part = from_string(
|
|
|
|
HELPDESK_EMAIL_SUBJECT_TEMPLATE % {
|
|
|
|
"subject": t.subject
|
|
|
|
}).render(context).replace('\n', '').replace('\r', '')
|
|
|
|
|
|
|
|
footer_file = os.path.join('helpdesk', locale, 'email_text_footer.txt')
|
|
|
|
|
|
|
|
text_part = from_string(
|
2020-10-30 19:57:23 +01:00
|
|
|
"%s\n\n{%% include '%s' %%}" % (t.plain_text, footer_file)
|
2018-10-31 16:24:57 +01:00
|
|
|
).render(context)
|
|
|
|
|
2022-07-12 12:34:19 +02:00
|
|
|
email_html_base_file = os.path.join(
|
|
|
|
'helpdesk', locale, 'email_html_base.html')
|
2018-10-31 16:24:57 +01:00
|
|
|
# keep new lines in html emails
|
|
|
|
if 'comment' in context:
|
2022-07-12 12:34:19 +02:00
|
|
|
context['comment'] = mark_safe(
|
|
|
|
context['comment'].replace('\r\n', '<br>'))
|
2018-10-31 16:24:57 +01:00
|
|
|
|
|
|
|
html_part = from_string(
|
2020-10-30 19:57:23 +01:00
|
|
|
"{%% extends '%s' %%}"
|
|
|
|
"{%% block title %%}%s{%% endblock %%}"
|
|
|
|
"{%% block content %%}%s{%% endblock %%}" %
|
2018-10-31 16:24:57 +01:00
|
|
|
(email_html_base_file, t.heading, t.html)
|
|
|
|
).render(context)
|
|
|
|
|
|
|
|
if isinstance(recipients, str):
|
|
|
|
if recipients.find(','):
|
|
|
|
recipients = recipients.split(',')
|
2023-10-10 15:08:47 +02:00
|
|
|
elif type(recipients) is not list:
|
2018-10-31 16:24:57 +01:00
|
|
|
recipients = [recipients]
|
|
|
|
|
|
|
|
msg = EmailMultiAlternatives(subject_part, text_part,
|
|
|
|
sender or settings.DEFAULT_FROM_EMAIL,
|
2021-04-15 10:39:55 +02:00
|
|
|
recipients, bcc=bcc,
|
|
|
|
headers=headers)
|
2018-10-31 16:24:57 +01:00
|
|
|
msg.attach_alternative(html_part, "text/html")
|
|
|
|
|
|
|
|
if files:
|
|
|
|
for filename, filefield in files:
|
2019-03-27 17:38:00 +01:00
|
|
|
filefield.open('rb')
|
|
|
|
content = filefield.read()
|
|
|
|
msg.attach(filename, content)
|
|
|
|
filefield.close()
|
2018-10-31 16:24:57 +01:00
|
|
|
logger.debug('Sending email to: {!r}'.format(recipients))
|
|
|
|
|
|
|
|
try:
|
|
|
|
return msg.send()
|
|
|
|
except SMTPException as e:
|
2022-07-12 12:34:19 +02:00
|
|
|
logger.exception(
|
|
|
|
'SMTPException raised while sending email to {}'.format(recipients))
|
2018-10-31 16:24:57 +01:00
|
|
|
if not fail_silently:
|
|
|
|
raise e
|
|
|
|
return 0
|