From 6e696b85663cc7c9bd6f1423ccf3b2dea40b786a Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Thu, 20 Jun 2024 17:42:25 -0400 Subject: [PATCH] SendGrid: report dropped "Bounced Address" webhook events as reason "bounced" In SendGrid tracking webhook, handle event="dropped", reason="Bounced Address" events as type "dropped", reject_reason "bounced" (rather than reject_reason "other"). See https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event#dropped --- CHANGELOG.rst | 8 ++++++++ anymail/webhooks/sendgrid.py | 1 + tests/test_sendgrid_webhooks.py | 34 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f93e9e78..89690138 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -52,6 +52,13 @@ Features and ``tags`` when sending with a ``template_id``. (Requires boto3 v1.34.98 or later.) +Fixes +~~~~~ + +* **SendGrid:** In the tracking webhook, correctly report "bounced address" + (recipients dropped due to earlier bounces) as reject reason ``"bounced"``. + (Thanks to `@vitaliyf`_.) + v10.3 ----- @@ -1672,4 +1679,5 @@ Features .. _@Tobeyforce: https://github.com/Tobeyforce .. _@varche1: https://github.com/varche1 .. _@vgrebenschikov: https://github.com/vgrebenschikov +.. _@vitaliyf: https://github.com/vitaliyf .. _@yourcelf: https://github.com/yourcelf diff --git a/anymail/webhooks/sendgrid.py b/anymail/webhooks/sendgrid.py index 8f085479..0e8b44d6 100644 --- a/anymail/webhooks/sendgrid.py +++ b/anymail/webhooks/sendgrid.py @@ -46,6 +46,7 @@ def parse_events(self, request): "invalid": RejectReason.INVALID, "unsubscribed address": RejectReason.UNSUBSCRIBED, "bounce": RejectReason.BOUNCED, + "bounced address": RejectReason.BOUNCED, "blocked": RejectReason.BLOCKED, "expired": RejectReason.TIMED_OUT, } diff --git a/tests/test_sendgrid_webhooks.py b/tests/test_sendgrid_webhooks.py index 6b939d8a..428d84d8 100644 --- a/tests/test_sendgrid_webhooks.py +++ b/tests/test_sendgrid_webhooks.py @@ -144,6 +144,40 @@ def test_dropped_invalid_event(self): self.assertEqual(event.reject_reason, "invalid") self.assertEqual(event.mta_response, None) + def test_dropped_bounced(self): + # https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event#dropped + raw_events = [ + { + "email": "example@example.com", + "timestamp": 1513299569, + "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-555>", + "event": "dropped", + "category": "cat facts", + "sg_event_id": "zmzJhfJgAfUSOW80yEbPyw==", + "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B88.0", + "reason": "Bounced Address", + "status": "5.0.0", + } + ] + response = self.client.post( + "/anymail/sendgrid/tracking/", + content_type="application/json", + data=json.dumps(raw_events), + ) + self.assertEqual(response.status_code, 200) + kwargs = self.assert_handler_called_once_with( + self.tracking_handler, + sender=SendGridTrackingWebhookView, + event=ANY, + esp_name="SendGrid", + ) + event = kwargs["event"] + self.assertIsInstance(event, AnymailTrackingEvent) + self.assertEqual(event.event_type, "rejected") + self.assertEqual(event.esp_event, raw_events[0]) + self.assertEqual(event.recipient, "example@example.com") + self.assertEqual(event.reject_reason, "bounced") + def test_dropped_unsubscribed_event(self): raw_events = [ {