Support Postmark delivery event webhook.

Add support for Postmark's recently-released [delivery tracking webhook] to Anymail's normailized status event handling. The existing Anymail tracking webhook URL can be copied to "Delivery webhook" in your Postmark outbound server settings.

Closes #45.
This commit is contained in:
medmunds
2016-12-15 14:23:44 -08:00
parent d0596d100b
commit 52596394cc
3 changed files with 33 additions and 6 deletions

View File

@@ -62,6 +62,8 @@ class PostmarkTrackingWebhookView(PostmarkBaseWebhookView):
except KeyError:
if 'FirstOpen' in esp_event:
event_type = EventType.OPENED
elif 'DeliveredAt' in esp_event:
event_type = EventType.DELIVERED
elif 'From' in esp_event:
# This is an inbound event
raise AnymailConfigurationError(
@@ -73,7 +75,7 @@ class PostmarkTrackingWebhookView(PostmarkBaseWebhookView):
recipient = getfirst(esp_event, ['Email', 'Recipient'], None) # Email for bounce; Recipient for open
try:
timestr = getfirst(esp_event, ['BouncedAt', 'ReceivedAt'])
timestr = getfirst(esp_event, ['DeliveredAt', 'BouncedAt', 'ReceivedAt'])
except KeyError:
timestamp = None
else:

View File

@@ -177,8 +177,8 @@ Status tracking webhooks
If you are using Anymail's normalized :ref:`status tracking <event-tracking>`, enter
the url in your `Postmark account settings`_, under Servers > *your server name* >
Settings > Outbound > Webhooks. You should enter this same Anymail tracking URL
for both the "Bounce webhook" and "Opens webhook" (if you want to receive both
types of events):
for all of the "Delivery webhook," "Bounce webhook," and "Opens webhook" (if you
want to receive all these types of events):
:samp:`https://{random}:{random}@{yoursite.example.com}/anymail/postmark/tracking/`
@@ -192,11 +192,12 @@ If you use multiple Postmark servers, you'll need to repeat entering the webhook
settings for each of them.
Postmark will report these Anymail :attr:`~anymail.signals.AnymailTrackingEvent.event_type`\s:
rejected, failed, bounced, deferred, autoresponded, opened, complained, unsubscribed, subscribed.
(Postmark does not support sent, delivered, or clicked events.)
rejected, failed, bounced, deferred, delivered, autoresponded, opened, complained,
unsubscribed, subscribed. (Postmark does not support sent or clicked events.)
The event's :attr:`~anymail.signals.AnymailTrackingEvent.esp_event` field will be
a `dict` of Postmark `bounce <http://developer.postmarkapp.com/developer-bounce-webhook.html>`_
a `dict` of Postmark `delivery <http://developer.postmarkapp.com/developer-delivery-webhook.html>`_,
`bounce <http://developer.postmarkapp.com/developer-bounce-webhook.html>`_,
or `open <http://developer.postmarkapp.com/developer-open-webhook.html>`_ webhook data.
.. _Postmark account settings: https://account.postmarkapp.com/servers

View File

@@ -55,6 +55,30 @@ class PostmarkDeliveryTestCase(WebhookTestCase):
self.assertEqual(event.mta_response,
"smtp;550 5.1.1 The email account that you tried to reach does not exist.")
def test_delivered_event(self):
raw_event = {
"ServerId": 23,
"MessageID": "883953f4-6105-42a2-a16a-77a8eac79483",
"Recipient": "recipient@example.com",
"Tag": "welcome-email",
"DeliveredAt": "2014-08-01T13:28:10.2735393-04:00",
"Details": "Test delivery webhook details"
}
response = self.client.post('/anymail/postmark/tracking/',
content_type='application/json', data=json.dumps(raw_event))
self.assertEqual(response.status_code, 200)
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=PostmarkTrackingWebhookView,
event=ANY, esp_name='Postmark')
event = kwargs['event']
self.assertIsInstance(event, AnymailTrackingEvent)
self.assertEqual(event.event_type, "delivered")
self.assertEqual(event.esp_event, raw_event)
self.assertEqual(event.timestamp, datetime(2014, 8, 1, 13, 28, 10, microsecond=273539,
tzinfo=get_fixed_timezone(-4*60)))
self.assertEqual(event.message_id, "883953f4-6105-42a2-a16a-77a8eac79483")
self.assertEqual(event.recipient, "recipient@example.com")
self.assertEqual(event.tags, ["welcome-email"])
def test_open_event(self):
raw_event = {
"FirstOpen": True,