Files
django-anymail/anymail/signals.py
medmunds b4e22c63b3 Reformat code with automated tools
Apply standardized code style
2023-02-06 15:05:24 -08:00

150 lines
4.1 KiB
Python

from django.dispatch import Signal
#: Outbound message, before sending
#: provides args: message, esp_name
pre_send = Signal()
#: Outbound message, after sending
#: provides args: message, status, esp_name
post_send = Signal()
#: Delivery and tracking events for sent messages
#: provides args: event, esp_name
tracking = Signal()
#: Event for receiving inbound messages
#: provides args: event, esp_name
inbound = Signal()
class AnymailEvent:
"""Base class for normalized Anymail webhook events"""
def __init__(
self, event_type, timestamp=None, event_id=None, esp_event=None, **kwargs
):
#: normalized to an EventType str
self.event_type = event_type
#: normalized to an aware datetime
self.timestamp = timestamp
#: opaque str
self.event_id = event_id
#: raw event fields (e.g., parsed JSON dict or POST data QueryDict)
self.esp_event = esp_event
class AnymailTrackingEvent(AnymailEvent):
"""Normalized delivery and tracking event for sent messages"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.click_url = kwargs.pop("click_url", None) #: str
#: str, usually human-readable, not normalized
self.description = kwargs.pop("description", None)
self.message_id = kwargs.pop("message_id", None) #: str, format may vary
self.metadata = kwargs.pop("metadata", {}) #: dict
#: str, may include SMTP codes, not normalized
self.mta_response = kwargs.pop("mta_response", None)
#: str email address (just the email portion; no name)
self.recipient = kwargs.pop("recipient", None)
#: normalized to a RejectReason str
self.reject_reason = kwargs.pop("reject_reason", None)
self.tags = kwargs.pop("tags", []) #: list of str
self.user_agent = kwargs.pop("user_agent", None) #: str
class AnymailInboundEvent(AnymailEvent):
"""Normalized inbound message event"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
#: anymail.inbound.AnymailInboundMessage
self.message = kwargs.pop("message", None)
class EventType:
"""Constants for normalized Anymail event types"""
# Delivery (and non-delivery) event types
# (these match message.ANYMAIL_STATUSES where appropriate)
#: the ESP has accepted the message and will try to send it (possibly later)
QUEUED = "queued"
#: the ESP has sent the message (though it may or may not get delivered)
SENT = "sent"
#: the ESP refused to send the message
#: (e.g., suppression list, policy, invalid email)
REJECTED = "rejected"
#: the ESP was unable to send the message (e.g., template rendering error)
FAILED = "failed"
#: rejected or blocked by receiving MTA
BOUNCED = "bounced"
#: delayed by receiving MTA; should be followed by a later BOUNCED or DELIVERED
DEFERRED = "deferred"
#: accepted by receiving MTA
DELIVERED = "delivered"
#: a bot replied
AUTORESPONDED = "autoresponded"
# Tracking event types
#: open tracking
OPENED = "opened"
#: click tracking
CLICKED = "clicked"
#: recipient reported as spam (e.g., through feedback loop)
COMPLAINED = "complained"
#: recipient attempted to unsubscribe
UNSUBSCRIBED = "unsubscribed"
#: signed up for mailing list through ESP-hosted form
SUBSCRIBED = "subscribed"
# Inbound event types
#: received message
INBOUND = "inbound"
#: (ESP notification of) error receiving message
INBOUND_FAILED = "inbound_failed"
# Other event types
#: all other ESP events
UNKNOWN = "unknown"
class RejectReason:
"""Constants for normalized Anymail reject/drop reasons"""
#: bad address format
INVALID = "invalid"
#: (previous) bounce from recipient
BOUNCED = "bounced"
#: (previous) repeated failed delivery attempts
TIMED_OUT = "timed_out"
#: ESP policy suppression
BLOCKED = "blocked"
#: (previous) spam complaint from recipient
SPAM = "spam"
#: (previous) unsubscribe request from recipient
UNSUBSCRIBED = "unsubscribed"
#: all other ESP reject reasons
OTHER = "other"