|
1 | 1 | from django.dispatch import Signal |
2 | 2 |
|
3 | | -webhook_event = Signal(providing_args=['event_type', 'data']) |
| 3 | + |
| 4 | +# Delivery and tracking events for sent messages |
| 5 | +tracking = Signal(providing_args=['event', 'esp_name']) |
| 6 | + |
| 7 | +# Event for receiving inbound messages |
| 8 | +inbound = Signal(providing_args=['event', 'esp_name']) |
| 9 | + |
| 10 | + |
| 11 | +class AnymailEvent(object): |
| 12 | + """Base class for normalized Anymail webhook events""" |
| 13 | + |
| 14 | + def __init__(self, event_type, timestamp=None, event_id=None, esp_event=None, **kwargs): |
| 15 | + self.event_type = event_type # normalized to an EventType str |
| 16 | + self.timestamp = timestamp # normalized to an aware datetime |
| 17 | + self.event_id = event_id # opaque str |
| 18 | + self.esp_event = esp_event # raw event fields (e.g., parsed JSON dict or POST data QueryDict) |
| 19 | + |
| 20 | + |
| 21 | +class AnymailTrackingEvent(AnymailEvent): |
| 22 | + """Normalized delivery and tracking event for sent messages""" |
| 23 | + |
| 24 | + def __init__(self, **kwargs): |
| 25 | + super(AnymailTrackingEvent, self).__init__(**kwargs) |
| 26 | + self.click_url = kwargs.pop('click_url', None) # str |
| 27 | + self.description = kwargs.pop('description', None) # str, usually human-readable, not normalized |
| 28 | + self.message_id = kwargs.pop('message_id', None) # str, format may vary |
| 29 | + self.metadata = kwargs.pop('metadata', None) # dict |
| 30 | + self.mta_response = kwargs.pop('mta_response', None) # str, may include SMTP codes, not normalized |
| 31 | + self.recipient = kwargs.pop('recipient', None) # str email address (just the email portion; no name) |
| 32 | + self.reject_reason = kwargs.pop('reject_reason', None) # normalized to a RejectReason str |
| 33 | + self.tags = kwargs.pop('tags', None) # list of str |
| 34 | + self.user_agent = kwargs.pop('user_agent', None) # str |
| 35 | + |
| 36 | + |
| 37 | +class AnymailInboundEvent(AnymailEvent): |
| 38 | + """Normalized inbound message event""" |
| 39 | + |
| 40 | + def __init__(self, **kwargs): |
| 41 | + super(AnymailInboundEvent, self).__init__(**kwargs) |
| 42 | + |
| 43 | + |
| 44 | +class EventType: |
| 45 | + """Constants for normalized Anymail event types""" |
| 46 | + |
| 47 | + # Delivery (and non-delivery) event types: |
| 48 | + # (these match message.ANYMAIL_STATUSES where appropriate) |
| 49 | + QUEUED = 'queued' # the ESP has accepted the message and will try to send it (possibly later) |
| 50 | + SENT = 'sent' # the ESP has sent the message (though it may or may not get delivered) |
| 51 | + REJECTED = 'rejected' # the ESP refused to send the messsage (e.g., suppression list, policy, invalid email) |
| 52 | + FAILED = 'failed' # the ESP was unable to send the message (e.g., template rendering error) |
| 53 | + |
| 54 | + BOUNCED = 'bounced' # rejected or blocked by receiving MTA |
| 55 | + DEFERRED = 'deferred' # delayed by receiving MTA; should be followed by a later BOUNCED or DELIVERED |
| 56 | + DELIVERED = 'delivered' # accepted by receiving MTA |
| 57 | + AUTORESPONDED = 'autoresponded' # a bot replied |
| 58 | + |
| 59 | + # Tracking event types: |
| 60 | + OPENED = 'opened' # open tracking |
| 61 | + CLICKED = 'clicked' # click tracking |
| 62 | + COMPLAINED = 'complained' # recipient reported as spam (e.g., through feedback loop) |
| 63 | + UNSUBSCRIBED = 'unsubscribed' # recipient attempted to unsubscribe |
| 64 | + SUBSCRIBED = 'subscribed' # signed up for mailing list through ESP-hosted form |
| 65 | + |
| 66 | + # Inbound event types: |
| 67 | + INBOUND = 'inbound' # received message |
| 68 | + INBOUND_FAILED = 'inbound_failed' |
| 69 | + |
| 70 | + # Other: |
| 71 | + UNKNOWN = 'unknown' # anything else |
| 72 | + |
| 73 | + |
| 74 | +class RejectReason: |
| 75 | + """Constants for normalized Anymail reject/drop reasons""" |
| 76 | + INVALID = 'invalid' # bad address format |
| 77 | + BOUNCED = 'bounced' # (previous) bounce from recipient |
| 78 | + TIMED_OUT = 'timed_out' # (previous) repeated failed delivery attempts |
| 79 | + BLOCKED = 'blocked' # ESP policy suppression |
| 80 | + SPAM = 'spam' # (previous) spam complaint from recipient |
| 81 | + UNSUBSCRIBED = 'unsubscribed' # (previous) unsubscribe request from recipient |
| 82 | + OTHER = 'other' |
0 commit comments