Reformat code with automated tools

Apply standardized code style
This commit is contained in:
medmunds
2023-02-06 12:27:43 -08:00
committed by Mike Edmunds
parent 40891fcb4a
commit b4e22c63b3
94 changed files with 12936 additions and 7443 deletions

View File

@@ -2,11 +2,18 @@ import json
from django.utils.dateparse import parse_datetime
from .base import AnymailBaseWebhookView
from ..exceptions import AnymailConfigurationError
from ..inbound import AnymailInboundMessage
from ..signals import inbound, tracking, AnymailInboundEvent, AnymailTrackingEvent, EventType, RejectReason
from ..utils import getfirst, EmailAddress
from ..signals import (
AnymailInboundEvent,
AnymailTrackingEvent,
EventType,
RejectReason,
inbound,
tracking,
)
from ..utils import EmailAddress, getfirst
from .base import AnymailBaseWebhookView
class PostmarkBaseWebhookView(AnymailBaseWebhookView):
@@ -15,7 +22,7 @@ class PostmarkBaseWebhookView(AnymailBaseWebhookView):
esp_name = "Postmark"
def parse_events(self, request):
esp_event = json.loads(request.body.decode('utf-8'))
esp_event = json.loads(request.body.decode("utf-8"))
return [self.esp_to_anymail_event(esp_event)]
def esp_to_anymail_event(self, esp_event):
@@ -29,40 +36,44 @@ class PostmarkTrackingWebhookView(PostmarkBaseWebhookView):
event_record_types = {
# Map Postmark event RecordType --> Anymail normalized event type
'Bounce': EventType.BOUNCED, # but check Type field for further info (below)
'Click': EventType.CLICKED,
'Delivery': EventType.DELIVERED,
'Open': EventType.OPENED,
'SpamComplaint': EventType.COMPLAINED,
'SubscriptionChange': EventType.UNSUBSCRIBED,
'Inbound': EventType.INBOUND, # future, probably
"Bounce": EventType.BOUNCED, # but check Type field for further info (below)
"Click": EventType.CLICKED,
"Delivery": EventType.DELIVERED,
"Open": EventType.OPENED,
"SpamComplaint": EventType.COMPLAINED,
"SubscriptionChange": EventType.UNSUBSCRIBED,
"Inbound": EventType.INBOUND, # future, probably
}
event_types = {
# Map Postmark bounce/spam event Type --> Anymail normalized (event type, reject reason)
'HardBounce': (EventType.BOUNCED, RejectReason.BOUNCED),
'Transient': (EventType.DEFERRED, None),
'Unsubscribe': (EventType.UNSUBSCRIBED, RejectReason.UNSUBSCRIBED),
'Subscribe': (EventType.SUBSCRIBED, None),
'AutoResponder': (EventType.AUTORESPONDED, None),
'AddressChange': (EventType.AUTORESPONDED, None),
'DnsError': (EventType.DEFERRED, None), # "temporary DNS error"
'SpamNotification': (EventType.COMPLAINED, RejectReason.SPAM),
'OpenRelayTest': (EventType.DEFERRED, None), # Receiving MTA is testing Postmark
'Unknown': (EventType.UNKNOWN, None),
'SoftBounce': (EventType.BOUNCED, RejectReason.BOUNCED), # might also receive HardBounce later
'VirusNotification': (EventType.BOUNCED, RejectReason.OTHER),
'ChallengeVerification': (EventType.AUTORESPONDED, None),
'BadEmailAddress': (EventType.REJECTED, RejectReason.INVALID),
'SpamComplaint': (EventType.COMPLAINED, RejectReason.SPAM),
'ManuallyDeactivated': (EventType.REJECTED, RejectReason.BLOCKED),
'Unconfirmed': (EventType.REJECTED, None),
'Blocked': (EventType.REJECTED, RejectReason.BLOCKED),
'SMTPApiError': (EventType.FAILED, None), # could occur if user also using Postmark SMTP directly
'InboundError': (EventType.INBOUND_FAILED, None),
'DMARCPolicy': (EventType.REJECTED, RejectReason.BLOCKED),
'TemplateRenderingFailed': (EventType.FAILED, None),
'ManualSuppression': (EventType.UNSUBSCRIBED, RejectReason.UNSUBSCRIBED),
# Map Postmark bounce/spam event Type
# --> Anymail normalized (event type, reject reason)
"HardBounce": (EventType.BOUNCED, RejectReason.BOUNCED),
"Transient": (EventType.DEFERRED, None),
"Unsubscribe": (EventType.UNSUBSCRIBED, RejectReason.UNSUBSCRIBED),
"Subscribe": (EventType.SUBSCRIBED, None),
"AutoResponder": (EventType.AUTORESPONDED, None),
"AddressChange": (EventType.AUTORESPONDED, None),
"DnsError": (EventType.DEFERRED, None), # "temporary DNS error"
"SpamNotification": (EventType.COMPLAINED, RejectReason.SPAM),
# Receiving MTA is testing Postmark:
"OpenRelayTest": (EventType.DEFERRED, None),
"Unknown": (EventType.UNKNOWN, None),
# might also receive HardBounce later:
"SoftBounce": (EventType.BOUNCED, RejectReason.BOUNCED),
"VirusNotification": (EventType.BOUNCED, RejectReason.OTHER),
"ChallengeVerification": (EventType.AUTORESPONDED, None),
"BadEmailAddress": (EventType.REJECTED, RejectReason.INVALID),
"SpamComplaint": (EventType.COMPLAINED, RejectReason.SPAM),
"ManuallyDeactivated": (EventType.REJECTED, RejectReason.BLOCKED),
"Unconfirmed": (EventType.REJECTED, None),
"Blocked": (EventType.REJECTED, RejectReason.BLOCKED),
# could occur if user also using Postmark SMTP directly:
"SMTPApiError": (EventType.FAILED, None),
"InboundError": (EventType.INBOUND_FAILED, None),
"DMARCPolicy": (EventType.REJECTED, RejectReason.BLOCKED),
"TemplateRenderingFailed": (EventType.FAILED, None),
"ManualSuppression": (EventType.UNSUBSCRIBED, RejectReason.UNSUBSCRIBED),
}
def esp_to_anymail_event(self, esp_event):
@@ -70,7 +81,7 @@ class PostmarkTrackingWebhookView(PostmarkBaseWebhookView):
try:
esp_record_type = esp_event["RecordType"]
except KeyError:
if 'FromFull' in esp_event:
if "FromFull" in esp_event:
# This is an inbound event
event_type = EventType.INBOUND
else:
@@ -81,59 +92,65 @@ class PostmarkTrackingWebhookView(PostmarkBaseWebhookView):
if event_type == EventType.INBOUND:
raise AnymailConfigurationError(
"You seem to have set Postmark's *inbound* webhook "
"to Anymail's Postmark *tracking* webhook URL.")
"to Anymail's Postmark *tracking* webhook URL."
)
if event_type in (EventType.BOUNCED, EventType.COMPLAINED):
# additional info is in the Type field
try:
event_type, reject_reason = self.event_types[esp_event['Type']]
event_type, reject_reason = self.event_types[esp_event["Type"]]
except KeyError:
pass
if event_type == EventType.UNSUBSCRIBED:
if esp_event['SuppressSending']:
if esp_event["SuppressSending"]:
# Postmark doesn't provide a way to distinguish between
# explicit unsubscribes and bounces
try:
event_type, reject_reason = self.event_types[esp_event['SuppressionReason']]
event_type, reject_reason = self.event_types[
esp_event["SuppressionReason"]
]
except KeyError:
pass
else:
event_type, reject_reason = self.event_types['Subscribe']
event_type, reject_reason = self.event_types["Subscribe"]
recipient = getfirst(esp_event, ['Email', 'Recipient'], None) # Email for bounce; Recipient for open
# Email for bounce; Recipient for open:
recipient = getfirst(esp_event, ["Email", "Recipient"], None)
try:
timestr = getfirst(esp_event, ['DeliveredAt', 'BouncedAt', 'ReceivedAt', 'ChangedAt'])
timestr = getfirst(
esp_event, ["DeliveredAt", "BouncedAt", "ReceivedAt", "ChangedAt"]
)
except KeyError:
timestamp = None
else:
timestamp = parse_datetime(timestr)
try:
event_id = str(esp_event['ID']) # only in bounce events
event_id = str(esp_event["ID"]) # only in bounce events
except KeyError:
event_id = None
metadata = esp_event.get('Metadata', {})
metadata = esp_event.get("Metadata", {})
try:
tags = [esp_event['Tag']]
tags = [esp_event["Tag"]]
except KeyError:
tags = []
return AnymailTrackingEvent(
description=esp_event.get('Description', None),
description=esp_event.get("Description", None),
esp_event=esp_event,
event_id=event_id,
event_type=event_type,
message_id=esp_event.get('MessageID', None),
message_id=esp_event.get("MessageID", None),
metadata=metadata,
mta_response=esp_event.get('Details', None),
mta_response=esp_event.get("Details", None),
recipient=recipient,
reject_reason=reject_reason,
tags=tags,
timestamp=timestamp,
user_agent=esp_event.get('UserAgent', None),
click_url=esp_event.get('OriginalLink', None),
user_agent=esp_event.get("UserAgent", None),
click_url=esp_event.get("OriginalLink", None),
)
@@ -146,12 +163,14 @@ class PostmarkInboundWebhookView(PostmarkBaseWebhookView):
if esp_event.get("RecordType", "Inbound") != "Inbound":
raise AnymailConfigurationError(
"You seem to have set Postmark's *%s* webhook "
"to Anymail's Postmark *inbound* webhook URL." % esp_event["RecordType"])
"to Anymail's Postmark *inbound* webhook URL." % esp_event["RecordType"]
)
attachments = [
AnymailInboundMessage.construct_attachment(
content_type=attachment["ContentType"],
content=attachment["Content"], base64=True,
content=attachment["Content"],
base64=True,
filename=attachment.get("Name", "") or None,
content_id=attachment.get("ContentID", "") or None,
)
@@ -160,11 +179,15 @@ class PostmarkInboundWebhookView(PostmarkBaseWebhookView):
message = AnymailInboundMessage.construct(
from_email=self._address(esp_event.get("FromFull")),
to=', '.join([self._address(to) for to in esp_event.get("ToFull", [])]),
cc=', '.join([self._address(cc) for cc in esp_event.get("CcFull", [])]),
# bcc? Postmark specs this for inbound events, but it's unclear how it could occur
to=", ".join([self._address(to) for to in esp_event.get("ToFull", [])]),
cc=", ".join([self._address(cc) for cc in esp_event.get("CcFull", [])]),
# bcc? Postmark specs this for inbound events,
# but it's unclear how it could occur
subject=esp_event.get("Subject", ""),
headers=[(header["Name"], header["Value"]) for header in esp_event.get("Headers", [])],
headers=[
(header["Name"], header["Value"])
for header in esp_event.get("Headers", [])
],
text=esp_event.get("TextBody", ""),
html=esp_event.get("HtmlBody", ""),
attachments=attachments,
@@ -176,36 +199,48 @@ class PostmarkInboundWebhookView(PostmarkBaseWebhookView):
if "ReplyTo" in esp_event and "Reply-To" not in message:
message["Reply-To"] = esp_event["ReplyTo"]
# Postmark doesn't have a separate envelope-sender field, but it can be extracted
# from the Received-SPF header that Postmark will have added:
if len(message.get_all("Received-SPF", [])) == 1: # (more than one? someone's up to something weird)
# Postmark doesn't have a separate envelope-sender field, but it can
# be extracted from the Received-SPF header that Postmark will have added.
# (More than one Received-SPF? someone's up to something weird?)
if len(message.get_all("Received-SPF", [])) == 1:
received_spf = message["Received-SPF"].lower()
if received_spf.startswith("pass") or received_spf.startswith("neutral"): # not fail/softfail
message.envelope_sender = message.get_param("envelope-from", None, header="Received-SPF")
if received_spf.startswith( # not fail/softfail
"pass"
) or received_spf.startswith("neutral"):
message.envelope_sender = message.get_param(
"envelope-from", None, header="Received-SPF"
)
message.envelope_recipient = esp_event.get("OriginalRecipient", None)
message.stripped_text = esp_event.get("StrippedTextReply", None)
message.spam_detected = message.get('X-Spam-Status', 'No').lower() == 'yes'
message.spam_detected = message.get("X-Spam-Status", "No").lower() == "yes"
try:
message.spam_score = float(message['X-Spam-Score'])
message.spam_score = float(message["X-Spam-Score"])
except (TypeError, ValueError):
pass
return AnymailInboundEvent(
event_type=EventType.INBOUND,
timestamp=None, # Postmark doesn't provide inbound event timestamp
event_id=esp_event.get("MessageID", None), # Postmark uuid, different from Message-ID mime header
# Postmark doesn't provide inbound event timestamp:
timestamp=None,
# Postmark uuid, different from Message-ID mime header:
event_id=esp_event.get("MessageID", None),
esp_event=esp_event,
message=message,
)
@staticmethod
def _address(full):
"""Return an formatted email address from a Postmark inbound {From,To,Cc}Full dict"""
"""
Return a formatted email address
from a Postmark inbound {From,To,Cc}Full dict
"""
if full is None:
return ""
return str(EmailAddress(
display_name=full.get('Name', ""),
addr_spec=full.get("Email", ""),
))
return str(
EmailAddress(
display_name=full.get("Name", ""),
addr_spec=full.get("Email", ""),
)
)