mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
Mailgun: treat temporary failure as deferred in tracking webhook
Map Mailgun severity: temporary failure event to Anymail "deferred" event, to distinguish it from severity: permanent failures which will show up as Anymail "bounced". Also remap Mailgun reason: generic failure to Anymail "other" reject reason (rather than "bounced"). Closes #130
This commit is contained in:
committed by
Mike Edmunds
parent
56c11ce387
commit
bb257152be
@@ -87,16 +87,20 @@ class MailgunTrackingWebhookView(MailgunBaseWebhookView):
|
|||||||
# (these appear in webhook doc examples, but aren't actually documented anywhere)
|
# (these appear in webhook doc examples, but aren't actually documented anywhere)
|
||||||
"bounce": RejectReason.BOUNCED,
|
"bounce": RejectReason.BOUNCED,
|
||||||
"suppress-bounce": RejectReason.BOUNCED,
|
"suppress-bounce": RejectReason.BOUNCED,
|
||||||
"generic": RejectReason.BOUNCED, # ??? appears to be used for any temporary failure?
|
"generic": RejectReason.OTHER, # ??? appears to be used for any temporary failure?
|
||||||
|
}
|
||||||
|
|
||||||
|
severities = {
|
||||||
|
# Remap some event types based on "severity" payload field
|
||||||
|
(EventType.BOUNCED, 'temporary'): EventType.DEFERRED
|
||||||
}
|
}
|
||||||
|
|
||||||
def esp_to_anymail_event(self, esp_event):
|
def esp_to_anymail_event(self, esp_event):
|
||||||
event_data = esp_event.get('event-data', {})
|
event_data = esp_event.get('event-data', {})
|
||||||
|
|
||||||
try:
|
event_type = self.event_types.get(event_data['event'], EventType.UNKNOWN)
|
||||||
event_type = self.event_types[event_data['event']]
|
|
||||||
except KeyError:
|
event_type = self.severities.get((EventType.BOUNCED, event_data.get('severity')), event_type)
|
||||||
event_type = EventType.UNKNOWN
|
|
||||||
|
|
||||||
# Use signature.token for event_id, rather than event_data.id,
|
# Use signature.token for event_id, rather than event_data.id,
|
||||||
# because the latter is only "guaranteed to be unique within a day".
|
# because the latter is only "guaranteed to be unique within a day".
|
||||||
|
|||||||
@@ -251,12 +251,52 @@ class MailgunTestCase(WebhookTestCase):
|
|||||||
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=MailgunTrackingWebhookView,
|
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=MailgunTrackingWebhookView,
|
||||||
event=ANY, esp_name='Mailgun')
|
event=ANY, esp_name='Mailgun')
|
||||||
event = kwargs['event']
|
event = kwargs['event']
|
||||||
self.assertEqual(event.event_type, "bounced")
|
self.assertEqual(event.event_type, "deferred")
|
||||||
self.assertEqual(event.recipient, "undeliverable@nomx.example.com")
|
self.assertEqual(event.recipient, "undeliverable@nomx.example.com")
|
||||||
self.assertEqual(event.reject_reason, "bounced")
|
self.assertEqual(event.reject_reason, "other")
|
||||||
self.assertEqual(event.description, "No MX for nomx.example.com")
|
self.assertEqual(event.description, "No MX for nomx.example.com")
|
||||||
self.assertEqual(event.mta_response, "No MX for nomx.example.com")
|
self.assertEqual(event.mta_response, "No MX for nomx.example.com")
|
||||||
|
|
||||||
|
def test_failed_greylisted_event(self):
|
||||||
|
raw_event = mailgun_sign_payload({
|
||||||
|
"event-data": {
|
||||||
|
"event": "failed",
|
||||||
|
"severity": "temporary",
|
||||||
|
"reason": "greylisted",
|
||||||
|
"timestamp": 1534111899.659519,
|
||||||
|
"log-level": "warn",
|
||||||
|
"message": {
|
||||||
|
"headers": {
|
||||||
|
"to": "undeliverable@nomx.example.com",
|
||||||
|
"message-id": "20180812214638.1.4A7D468E9BC18C5D@example.org",
|
||||||
|
"from": "Test Sender ",
|
||||||
|
"subject": "Testing"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"recipient": "undeliverable@mx.example.com",
|
||||||
|
"delivery-status": {
|
||||||
|
"mx-host": "mx.example.com",
|
||||||
|
"attempt-no": 1,
|
||||||
|
"description": "Recipient address rejected: Greylisted",
|
||||||
|
"session-seconds": 0.0,
|
||||||
|
"retry-seconds": 300,
|
||||||
|
"code": 450,
|
||||||
|
"message": "Recipient address rejected: Greylisted"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
response = self.client.post('/anymail/mailgun/tracking/',
|
||||||
|
data=json.dumps(raw_event), content_type='application/json')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=MailgunTrackingWebhookView,
|
||||||
|
event=ANY, esp_name='Mailgun')
|
||||||
|
event = kwargs['event']
|
||||||
|
self.assertEqual(event.event_type, "deferred")
|
||||||
|
self.assertEqual(event.recipient, "undeliverable@mx.example.com")
|
||||||
|
self.assertEqual(event.reject_reason, "other")
|
||||||
|
self.assertEqual(event.description, "Recipient address rejected: Greylisted")
|
||||||
|
self.assertEqual(event.mta_response, "Recipient address rejected: Greylisted")
|
||||||
|
|
||||||
def test_rejected_event(self):
|
def test_rejected_event(self):
|
||||||
# (The "rejected" event is documented and appears in Mailgun dashboard logs,
|
# (The "rejected" event is documented and appears in Mailgun dashboard logs,
|
||||||
# but it doesn't appear to be delivered through webhooks as of 8/2018.)
|
# but it doesn't appear to be delivered through webhooks as of 8/2018.)
|
||||||
|
|||||||
Reference in New Issue
Block a user