Postmark: workaround invalid "test inbound" data

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
This commit is contained in:
Therry van Neerven
2023-04-22 21:00:05 +02:00
committed by GitHub
parent d9a80e7347
commit 885eb9b98a
3 changed files with 55 additions and 9 deletions

View File

@@ -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
~~~~~

View File

@@ -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,
@@ -169,7 +170,13 @@ class PostmarkInboundWebhookView(PostmarkBaseWebhookView):
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,
@@ -177,6 +184,18 @@ class PostmarkInboundWebhookView(PostmarkBaseWebhookView):
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", [])]),

View File

@@ -4,7 +4,7 @@ from unittest.mock import ANY
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
@@ -165,14 +165,27 @@ class PostmarkInboundTestCase(WebhookTestCase):
"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,
@@ -183,7 +196,7 @@ class PostmarkInboundTestCase(WebhookTestCase):
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")
@@ -192,6 +205,14 @@ class PostmarkInboundTestCase(WebhookTestCase):
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"]