-
Notifications
You must be signed in to change notification settings - Fork 46
/
emails.py
164 lines (137 loc) · 5.33 KB
/
emails.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# Python Standard Library Imports
import inspect
# Third Party (PyPI) Imports
import rollbar
# Django Imports
from django.template import TemplateDoesNotExist
from django.template.loader import get_template
# HTK Imports
from htk.mailers import send_email
from htk.tasks import BaseTask
class BaseBatchRelationshipEmails(BaseTask):
"""
Relationship emails are related to transactional emails, but usually happen asynchronously or offline, apart from direct web requests
Examples:
- Daily or weekly updates
- Drip reminders
- Account status reports
- Shopping cart abandonment reminders
References:
- http://blog.mailchimp.com/what-is-transactional-email/
- https://www.ftc.gov/tips-advice/business-center/guidance/can-spam-act-compliance-guide-business
"""
def __init__(self, cooldown_class=None, template=None):
# set cooldown_class
from htk.cachekeys import BatchRelationshipEmailCooldown
if inspect.isclass(cooldown_class) and issubclass(cooldown_class, BatchRelationshipEmailCooldown):
self.cooldown_class = cooldown_class
else:
self.cooldown_class = BatchRelationshipEmailCooldown
# set template
if template:
self.template = template
template_name = 'emails/%s.html' % template
# try to get the template... otherwise fail now before processing emails
tpl = get_template(template_name)
self.tpl = tpl
else:
raise TemplateDoesNotExist('Unspecified template')
def get_email_batch_cooldown_prekey(self, user, **kwargs):
prekey = ['email_batch', user.id,]
kw_values = [kwargs[key] for key in sorted(kwargs.keys())]
prekey += kw_values
return prekey
def has_email_batch_cooldown(self, user, **kwargs):
"""Checks whether cooldown timer is still going for the email batch for `user` and `kwargs`
"""
prekey = self.get_email_batch_cooldown_prekey(user, **kwargs)
c = self.cooldown_class(prekey)
_has_cooldown = bool(c.get())
return _has_cooldown
def reset_email_batch_cooldown(self, user, **kwargs):
"""Resets cooldown timer for email batch for `user` and `kwargs`
Returns whether cooldown was reset, False if timer was still running
"""
prekey = self.get_email_batch_cooldown_prekey(user, **kwargs)
c = self.cooldown_class(prekey)
if c.get():
was_reset = False
else:
c.cache_store()
was_reset = True
return was_reset
def get_users(self):
users = self.get_recipients()
return users
def get_recipient_email_batches_data(self, recipient):
"""Gets data about each email for the `recipient`
Use cases. A recipient can receive multiple emails if:
- recipient has multiple "sub-accounts"
Returns a list of dictionaries
"""
return [{}]
def get_recipients(self):
"""Returns a list or QuerySet of User objects
Should be overridden
"""
users = super(BaseTask, self).get_users()
return users
def execute(self, user):
"""Send out emails for `user`
One `user` may receive one or many emails
"""
recipient = user
email_batches_data = self.get_recipient_email_batches_data(recipient)
for email_batch_data in email_batches_data:
try:
if self.has_email_batch_cooldown(recipient, **email_batch_data):
pass
else:
self.send_email(recipient, **email_batch_data)
self.reset_email_batch_cooldown(recipient, **email_batch_data)
except:
extra_data = {
'user' : user,
'email_batch_data' : email_batch_data,
}
rollbar.report_exc_info(extra_data=extra_data)
def send_email(self, recipient, **kwargs):
"""Workhorse function called by `self.send_emails` for
sending to one `recipient`
Can be overridden
"""
email_params = self._craft_email_params(recipient, **kwargs)
context = email_params.get('context', {})
send_email(
template=email_params.get('template'),
subject=context.get('subject'),
to=email_params.get('recipients', []),
context=context
)
def get_subject(self, recipient, **kwargs):
"""Returns the email subject line for `recipient`
Should be overridden
"""
subject = ''
return subject
def get_email_context(self, recipient, **kwargs):
"""Returns a dictionary for the email context
"""
context = {}
return context
def _craft_email_params(self, recipient, **kwargs):
"""Build the email params for rendering this BatchRelationshipEmail
"""
recipients = [recipient.email,]
subject = self.get_subject(recipient, **kwargs)
context = {
'user' : recipient,
'subject' : subject,
}
context.update(self.get_email_context(recipient, **kwargs))
email_params = {
'template' : self.template,
'recipients' : recipients,
'context' : context,
}
return email_params