diff --git a/anymail/webhooks/postmark.py b/anymail/webhooks/postmark.py index be34b4a..466bdfc 100644 --- a/anymail/webhooks/postmark.py +++ b/anymail/webhooks/postmark.py @@ -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: diff --git a/docs/esps/postmark.rst b/docs/esps/postmark.rst index 14f5c9a..e00b165 100644 --- a/docs/esps/postmark.rst +++ b/docs/esps/postmark.rst @@ -177,8 +177,8 @@ Status tracking webhooks If you are using Anymail's normalized :ref:`status 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 `_ +a `dict` of Postmark `delivery `_, +`bounce `_, or `open `_ webhook data. .. _Postmark account settings: https://account.postmarkapp.com/servers diff --git a/tests/test_postmark_webhooks.py b/tests/test_postmark_webhooks.py index 40a7a11..85c657e 100644 --- a/tests/test_postmark_webhooks.py +++ b/tests/test_postmark_webhooks.py @@ -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,