Skip to content

Commit

Permalink
Postmark: workaround invalid "test inbound" data
Browse files Browse the repository at this point in the history
Postmark's "test" button in their inbound settings
posts data with attachments that don't match their docs or
actual inbound behavior. Accept that and issue a warning.

Closes #304
  • Loading branch information
Ecno92 committed Apr 22, 2023
1 parent d9a80e7 commit 885eb9b
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 9 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ vNext

*Unreleased changes*

Fixes
~~~~~

* **Postmark:** Workaround for handling inbound test webhooks.
(`More info <https://github.com/anymail/django-anymail/issues/304>`__)

Other
~~~~~

Expand Down
23 changes: 21 additions & 2 deletions anymail/webhooks/postmark.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import json
import warnings

from django.utils.dateparse import parse_datetime

from ..exceptions import AnymailConfigurationError
from ..exceptions import AnymailConfigurationError, AnymailWarning
from ..inbound import AnymailInboundMessage
from ..signals import (
AnymailInboundEvent,
Expand Down Expand Up @@ -169,14 +170,32 @@ def esp_to_anymail_event(self, esp_event):
attachments = [
AnymailInboundMessage.construct_attachment(
content_type=attachment["ContentType"],
content=attachment["Content"],
content=(
attachment.get("Content")
# WORKAROUND:
# The test webhooks are not like their real webhooks
# This allows the test webhooks to be parsed.
or attachment["Data"]
),
base64=True,
filename=attachment.get("Name", "") or None,
content_id=attachment.get("ContentID", "") or None,
)
for attachment in esp_event.get("Attachments", [])
]

# Warning to the user regarding the workaround of above.
for attachment in esp_event.get("Attachments", []):
if "Data" in attachment:
warnings.warn(
"Received a test webhook attachment. "
"It is recommended to test with real inbound events. "
"See https://github.com/anymail/django-anymail/issues/304 "
"for more information.",
AnymailWarning,
)
break

message = AnymailInboundMessage.construct(
from_email=self._address(esp_event.get("FromFull")),
to=", ".join([self._address(to) for to in esp_event.get("ToFull", [])]),
Expand Down
35 changes: 28 additions & 7 deletions tests/test_postmark_inbound.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from django.test import tag

from anymail.exceptions import AnymailConfigurationError
from anymail.exceptions import AnymailConfigurationError, AnymailWarning
from anymail.inbound import AnymailInboundMessage
from anymail.signals import AnymailInboundEvent
from anymail.webhooks.postmark import PostmarkInboundWebhookView
Expand Down Expand Up @@ -165,14 +165,27 @@ def test_attachments(self):
"ContentType": 'message/rfc822; charset="us-ascii"',
"ContentLength": len(email_content),
},
# This is an attachement like send by the test webhook
# A workaround is implemented to handle it.
# Once Postmark solves the bug on their side this workaround
# can be reverted.
{
"Name": "test.txt",
"ContentType": "text/plain",
"Data": "VGhpcyBpcyBhdHRhY2htZW50IGNvbnRlbnRzLCBiYXNlLTY0IGVuY29kZWQu",
"ContentLength": 45,
},
]
}

response = self.client.post(
"/anymail/postmark/inbound/",
content_type="application/json",
data=json.dumps(raw_event),
)
with self.assertWarnsRegex(
AnymailWarning, r"Received a test webhook attachment. "
):
response = self.client.post(
"/anymail/postmark/inbound/",
content_type="application/json",
data=json.dumps(raw_event),
)
self.assertEqual(response.status_code, 200)
kwargs = self.assert_handler_called_once_with(
self.inbound_handler,
Expand All @@ -183,7 +196,7 @@ def test_attachments(self):
event = kwargs["event"]
message = event.message
attachments = message.attachments # AnymailInboundMessage convenience accessor
self.assertEqual(len(attachments), 2)
self.assertEqual(len(attachments), 3)
self.assertEqual(attachments[0].get_filename(), "test.txt")
self.assertEqual(attachments[0].get_content_type(), "text/plain")
self.assertEqual(attachments[0].get_content_text(), "test attachment")
Expand All @@ -192,6 +205,14 @@ def test_attachments(self):
attachments[1].get_content_bytes(), email_content
)

# Attachment of test webhook
self.assertEqual(attachments[2].get_filename(), "test.txt")
self.assertEqual(attachments[2].get_content_type(), "text/plain")
self.assertEqual(
attachments[2].get_content_text(),
"This is attachment contents, base-64 encoded.",
)

inlines = message.inline_attachments
self.assertEqual(len(inlines), 1)
inline = inlines["abc123"]
Expand Down

0 comments on commit 885eb9b

Please sign in to comment.