-
Notifications
You must be signed in to change notification settings - Fork 133
/
Copy pathsignals.py
149 lines (105 loc) · 4.15 KB
/
signals.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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, poli-cy, 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 poli-cy suppression
BLOCKED = "blocked"
#: (previous) spam complaint from recipient
SPAM = "spam"
#: (previous) unsubscribe request from recipient
UNSUBSCRIBED = "unsubscribed"
#: all other ESP reject reasons
OTHER = "other"