Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workaround for postmark inbound test email can not be parsed #309

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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