From 2c53344f1f4ac071749b4a9fd394c25d5ec031d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 23 Jan 2019 18:18:45 +0100 Subject: [PATCH] Add a helper to handle smtp errors in send_mass_mail --- utils/mailutils.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 utils/mailutils.py diff --git a/utils/mailutils.py b/utils/mailutils.py new file mode 100644 index 00000000..b52dddf2 --- /dev/null +++ b/utils/mailutils.py @@ -0,0 +1,54 @@ +from custommail.shortcuts import send_mass_custom_mail +from smtplib import SMTPRecipientsRefused + + +def drop_until(predicate, l): + """ + Drop the first elements of the list until we find the first element + satisfying the predicate, this element is also dropped. + """ + for i in range(len(l)): + if predicate(l[i]): + return l[i + 1:] + return [] + + +def intersects(list1, list2): + """ Return True iff there is one element in common in the two lists """ + return any(x in list2 for x in list1) + + +class SendMassMailRecipientRefused(Exception): + pass + + +def send_mass_custom_mail_wrapper(datatuple, *args, **kwargs): + """ + Similar to custommail.shortcuts.send_mass_custom_mail but if an + SMTPRecipientsRefused exception is encountered, finish processing the datatuple + and only raise at the end of the list. + Thus, only the faulty emails won't be sent. + """ + to_be_sent = datatuple + in_error = [] + + while to_be_sent: + try: + send_mass_custom_mail(to_be_sent, *args, **kwargs) + to_be_sent = [] + except SMTPRecipientsRefused as exn: + # A recipient error has been encountered: + # 1. drop already sent emails from the "to be sent" list + # 2. move the bogus email from the "to be sent" list to the "in error" list + # 3. try to send the remaining emails + refused_emails, = exn.args + + def predicate(tuple): + __, __, __, recipients = tuple + return intersects(refused_emails.keys(), recipients) + + to_be_sent = drop_until(predicate, to_be_sent) + in_error.append(refused_emails) + + if in_error: + raise SendMassMailRecipientRefused(in_error)