Compare commits

...

3 commits

Author SHA1 Message Date
Martin Pépin 727626cadd cosmetic: blackify and isortify 2019-01-24 11:15:24 +01:00
Martin Pépin 12c10847e7 use send_mass_custom_mail_wrapper for bda notifications 2019-01-23 18:19:54 +01:00
Martin Pépin 2c53344f1f Add a helper to handle smtp errors in send_mass_mail 2019-01-23 18:18:45 +01:00
3 changed files with 100 additions and 27 deletions

View file

@ -1,6 +1,5 @@
from datetime import timedelta
from custommail.shortcuts import send_mass_custom_mail
from dal.autocomplete import ModelSelect2
from django import forms
from django.contrib import admin
@ -19,6 +18,7 @@ from bda.models import (
SpectacleRevente,
Tirage,
)
from utils.mailutils import SendMassMailRecipientRefused, send_mass_custom_mail_wrapper
class ReadOnlyMixin(object):
@ -142,17 +142,28 @@ class ParticipantAdmin(ReadOnlyMixin, admin.ModelAdmin):
context["places"] = attribs
print(context)
datatuple.append((shortname, context, "bda@ens.fr", [member.user.email]))
send_mass_custom_mail(datatuple)
count = len(queryset.all())
if count == 1:
message_bit = "1 membre a"
plural = ""
else:
message_bit = "%d membres ont" % count
plural = "s"
self.message_user(
request, "%s été informé%s avec succès." % (message_bit, plural)
)
try:
send_mass_custom_mail_wrapper(datatuple)
except SendMassMailRecipientRefused as exn:
errors, = exn.args
faulty_emails = ", ".join(errors.keys())
count -= len(errors)
self.message_user(
request,
"Les emails suivant causent des erreurs: {}".format(faulty_emails),
)
raise
finally:
if count == 1:
message_bit = "[1/{}] membre a".format(len(queryset.all()))
plural = ""
else:
message_bit = "[{}/{}] membres ont".format(count, queryset.all())
plural = "s"
self.message_user(
request, "%s été informé%s avec succès." % (message_bit, plural)
)
send_attribs.short_description = "Envoyer les résultats par mail"

View file

@ -3,7 +3,6 @@ import random
from datetime import timedelta
from custommail.models import CustomMail
from custommail.shortcuts import send_mass_custom_mail
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
@ -12,6 +11,8 @@ from django.db import models
from django.db.models import Count
from django.utils import formats, timezone
from utils.mailutils import send_mass_custom_mail_wrapper
def get_generic_user():
generic, _ = User.objects.get_or_create(
@ -125,10 +126,12 @@ class Spectacle(models.Model):
)
for member in members
]
send_mass_custom_mail(datatuple)
# On enregistre le fait que l'envoi a bien eu lieu
self.rappel_sent = timezone.now()
self.save()
try:
send_mass_custom_mail_wrapper(datatuple)
finally:
# On enregistre le fait que l'envoi a bien eu lieu
self.rappel_sent = timezone.now()
self.save()
# On renvoie la liste des destinataires
return members
@ -343,10 +346,12 @@ class SpectacleRevente(models.Model):
)
for participant in inscrits
]
send_mass_custom_mail(datatuple)
self.notif_sent = True
self.notif_time = timezone.now()
self.save()
try:
send_mass_custom_mail_wrapper(datatuple)
finally:
self.notif_sent = True
self.notif_time = timezone.now()
self.save()
def mail_shotgun(self):
"""
@ -367,13 +372,15 @@ class SpectacleRevente(models.Model):
)
for participant in inscrits
]
send_mass_custom_mail(datatuple)
self.notif_sent = True
self.notif_time = timezone.now()
# Flag inutile, sauf si l'horloge interne merde
self.tirage_done = True
self.shotgun = True
self.save()
try:
send_mass_custom_mail_wrapper(datatuple)
finally:
self.notif_sent = True
self.notif_time = timezone.now()
# Flag inutile, sauf si l'horloge interne merde
self.tirage_done = True
self.shotgun = True
self.save()
def tirage(self, send_mails=True):
"""

55
utils/mailutils.py Normal file
View file

@ -0,0 +1,55 @@
from smtplib import SMTPRecipientsRefused
from custommail.shortcuts import send_mass_custom_mail
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)