From 3285d5e1a81bd194a8e4eb8f5a6cf41a0fb54fe4 Mon Sep 17 00:00:00 2001 From: Arkadiy Korotaev Date: Thu, 15 Apr 2021 10:39:55 +0200 Subject: [PATCH] feat(emails): Do not auto-reply on auto-replies and add auto-reply header for auto-replies and fix headers propagation for our email messages --- helpdesk/email.py | 67 ++++++++++++++++++++++++++----------- helpdesk/models.py | 3 +- helpdesk/templated_email.py | 7 ++-- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/helpdesk/email.py b/helpdesk/email.py index b1647e31..fcbb3b08 100644 --- a/helpdesk/email.py +++ b/helpdesk/email.py @@ -302,6 +302,21 @@ def decode_mail_headers(string): ]) +def is_autoreply(message): + """ + Accepting message as something with .get(header_name) method + Returns True if it's likely to be auto-reply or False otherwise + So we don't start mail loops + """ + any_if_this = [ + False if not message.get("Auto-Submitted") else message.get("Auto-Submitted").lower() != "no", + True if message.get("X-Auto-Response-Suppress") in ("DR", "AutoReply", "All") else False, + message.get("List-Id"), + message.get("List-Unsubscribe"), + ] + return any(any_if_this) + + def create_ticket_cc(ticket, cc_list): if not cc_list: @@ -429,30 +444,41 @@ def create_object_from_email_message(message, ticket_id, payload, files, logger) for email_address in ticket_cc_list: notifications_to_be_sent.append(email_address) - # send mail to appropriate people now depending on what objects - # were created and who was CC'd - if new: - ticket.send( - {'submitter': ('newticket_submitter', context), - 'new_ticket_cc': ('newticket_cc', context), - 'ticket_cc': ('newticket_cc', context)}, - fail_silently=True, - extra_headers={'In-Reply-To': message_id}, - ) + autoreply = is_autoreply(message) + if autoreply: + logger.info("Message seems to be auto-reply, not sending any emails back to the sender") else: - context.update(comment=f.comment) - ticket.send( - {'submitter': ('newticket_submitter', context), - 'assigned_to': ('updated_owner', context)}, - fail_silently=True, - extra_headers={'In-Reply-To': message_id}, - ) - if queue.enable_notifications_on_email_events: + # send mail to appropriate people now depending on what objects + # were created and who was CC'd + # Add auto-reply headers because it's an auto-reply and we must + extra_headers = { + 'In-Reply-To': message_id, + "Auto-Submitted": "auto-replied", + "X-Auto-Response-Suppress": "All", + "Precedence": "auto_reply", + } + if new: ticket.send( - {'ticket_cc': ('updated_cc', context)}, + {'submitter': ('newticket_submitter', context), + 'new_ticket_cc': ('newticket_cc', context), + 'ticket_cc': ('newticket_cc', context)}, fail_silently=True, - extra_headers={'In-Reply-To': message_id}, + extra_headers=extra_headers, ) + else: + context.update(comment=f.comment) + ticket.send( + {'submitter': ('newticket_submitter', context), + 'assigned_to': ('updated_owner', context)}, + fail_silently=True, + extra_headers=extra_headers, + ) + if queue.enable_notifications_on_email_events: + ticket.send( + {'ticket_cc': ('updated_cc', context)}, + fail_silently=True, + extra_headers=extra_headers, + ) return ticket @@ -469,6 +495,7 @@ def object_from_message(message, queue, logger): sender = message.get('from', _('Unknown Sender')) sender = decode_mail_headers(decodeUnknown(message.get_charset(), sender)) + # to address bug #832, we wrap all the text in front of the email address in # double quotes by using replace() on the email string. Then, # take first item of list, second item of tuple is the actual email address. diff --git a/helpdesk/models.py b/helpdesk/models.py index 4d6ff009..dbed2a56 100644 --- a/helpdesk/models.py +++ b/helpdesk/models.py @@ -614,7 +614,7 @@ class Ticket(models.Model): 'assigned_to': (template_name2, context), } - **kwargs are passed to send_templated_mail defined in templated_mail.py + **kwargs are passed to send_templated_mail defined in templated_email.py returns the set of email addresses the notification was delivered to. @@ -634,6 +634,7 @@ class Ticket(models.Model): template, context = roles[role] send_templated_mail(template, context, recipient, sender=self.queue.from_address, **kwargs) recipients.add(recipient) + send('submitter', self.submitter_email) send('ticket_cc', self.queue.updated_ticket_cc) send('new_ticket_cc', self.queue.new_ticket_cc) diff --git a/helpdesk/templated_email.py b/helpdesk/templated_email.py index 9ac92cff..4b20fc83 100644 --- a/helpdesk/templated_email.py +++ b/helpdesk/templated_email.py @@ -15,7 +15,7 @@ def send_templated_mail(template_name, bcc=None, fail_silently=False, files=None, - extra_headers={}): + extra_headers=None): """ 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 @@ -53,6 +53,8 @@ def send_templated_mail(template_name, from helpdesk.settings import HELPDESK_EMAIL_SUBJECT_TEMPLATE, \ HELPDESK_EMAIL_FALLBACK_LOCALE + headers = extra_headers or {} + locale = context['queue'].get('locale') or HELPDESK_EMAIL_FALLBACK_LOCALE try: @@ -95,7 +97,8 @@ def send_templated_mail(template_name, msg = EmailMultiAlternatives(subject_part, text_part, sender or settings.DEFAULT_FROM_EMAIL, - recipients, bcc=bcc) + recipients, bcc=bcc, + headers=headers) msg.attach_alternative(html_part, "text/html") if files: