Skip to content
Snippets Groups Projects
Commit 9703dbc7 authored by florimondmanca's avatar florimondmanca
Browse files

log errors in send_notification, limit subject length to 75 characters

parent 3ec6b982
Branches
No related tags found
No related merge requests found
# Environment variables used by `$ heroku local`
DJANGO_SETTINGS_MODULE=oser_backend.settings.dev
PORT=8000
web: sh -c 'cd oser_backend && exec gunicorn oser_backend.wsgi:application --bind 0.0.0.0:$PORT --workers 1'
# Toggle next line to start Celery in a worker process
worker: sh -c 'cd oser_backend && exec celery -A oser_backend worker --beat -l info'
# worker: sh -c 'cd oser_backend && exec celery -A oser_backend worker --beat -l info'
"""Render a notification."""
from .base import MailsCommandMixin
from ..base import MailsCommandMixin
from django.core.management import BaseCommand
......
"""Send a notification."""
from .base import MailsCommandMixin
from ..base import MailsCommandMixin
from django.core.management import BaseCommand
......@@ -12,17 +12,16 @@ class Command(MailsCommandMixin, BaseCommand):
def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument(
'recipient',
help='Email of the notification recipient.')
'recipient', help='Email of the notification recipient.')
def handle(self, *args, **kwargs):
recipient = kwargs['recipient']
notification = self.get_notification(kwargs)
notification.force_recipients([recipient])
result = notification.send()
if result['sent']:
notification.send()
if notification.sent:
self.stdout.write(self.style.SUCCESS(
f'✉️ Notification email sent to {recipient}.'))
f'Notification email sent to {recipient}.'))
else:
self.stderr.write(
'⚠️ Notification email not sent (see above for logs).')
'Notification email not sent (see above for logs).')
......@@ -8,10 +8,11 @@ from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.html import strip_tags
from django.utils.text import Truncator
from markdown import markdown
from .signals import app_disabled, delivered, notification_sent
from .signals import app_disabled, delivered, notification_sent, failed
def send_notification(subject, message, recipient_list,
......@@ -43,7 +44,12 @@ def send_notification(subject, message, recipient_list,
mail_from = settings.MAILS_NOTIFICATIONS_ADDRESS
try:
send_mail(subject, message, mail_from, recipient_list, **kwargs)
except Exception as e:
failed.send(None, exception=e)
return False
delivered.send(None, mail_from=mail_from,
recipient_list=recipient_list, subject=subject)
......@@ -167,6 +173,9 @@ class Notification:
def send(self) -> None:
"""Send the notification email."""
subject = self.subject_format.format(subject=self.get_subject())
# Subject must not be longer than 78 characters
# See https://github.com/sendgrid/sendgrid-python/issues/187
subject = Truncator(subject).chars(75)
message = self.render()
if self.forced:
......
"""Mails app signals."""
from django.dispatch import Signal, receiver
from python_http_client.exceptions import HTTPError
from logs import get_logger
delivered = Signal(providing_args=['mail_from', 'subject', 'recipient_list'])
app_disabled = Signal(providing_args=['subject', 'recipient_list'])
failed = Signal(providing_args=['exception'])
notification_sent = Signal(providing_args=['instance', 'result'])
logger = get_logger('notifications')
......@@ -22,3 +24,12 @@ def log_app_disabled(sender, subject, recipient_list, **kwargs):
logger.warning(
'Email "%s" not sent to %s because MAILS_ENABLED is set to False',
subject, recipient_list)
@receiver(failed)
def log_failed(sender, exception, **kwargs):
"""Log an exception that occurred during a mail delivery."""
if isinstance(exception, HTTPError):
logger.exception(exception.read())
else:
logger.exception(exception)
......@@ -22,7 +22,7 @@ def notify_participation(sender, instance: Participation, **kwargs):
The notification is only sent if the participation status has changed.
"""
if instance.accepted is True:
Accepted(user=instance.user, visit=instance.visit).send()
elif instance.accepted is False:
Rejected(user=instance.user, visit=instance.visit).send()
if instance.accepted is None:
return
notification_cls = Accepted if instance.accepted else Rejected
notification_cls(user=instance.user, visit=instance.visit).send()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment