forked from maximilianhurl/django-mail-templated
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path__init__.py
141 lines (116 loc) · 4.99 KB
/
__init__.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
from django.template.loader import get_template
from django.template.loader_tags import BlockNode, ExtendsNode
from django.template import Context
from django.core import mail
def _get_node(template, name, block_lookups={}):
"""
Get a named node from a template.
Returns `None` if a node with the given name does not exist.
taken from https://github.com/bradwhittington/django-templated-email/blob/master/templated_email/utils.py
"""
context = Context()
context.template = template
for node in template.nodelist:
if isinstance(node, BlockNode) and node.name == name:
for i in range(len(node.nodelist)):
n = node.nodelist[i]
if isinstance(n, BlockNode) and n.name in block_lookups:
node.nodelist[i] = block_lookups[n.name]
return node
elif isinstance(node, ExtendsNode):
lookups = dict([(n.name, n) for n in node.nodelist if isinstance(n, BlockNode)])
lookups.update(block_lookups)
return _get_node(node.get_parent(context), name, lookups)
return None
class EmailMessage(mail.EmailMultiAlternatives):
"""Extends standard EmailMessage class with ability to use templates"""
def __init__(self, template_name, context, *args, **kwargs):
self._subject = None
self._body = None
self._html = None
# This causes template loading.
self.template_name = template_name
# Save context to process on send().
self.context = context
super(EmailMessage, self).__init__(*args, **kwargs)
# It's not set by default, but we may ommit the html content.
self.alternatives = []
@property
def template_name(self):
return self._template_name
@template_name.setter
def template_name(self, value):
self._template_name = value
# Load the template.
self.template = get_template(self._template_name)
@property
def template(self):
return self._template
@template.setter
def template(self, value):
if hasattr(value, 'template'):
value = value.template
self._template = value
self._subject = _get_node(value, 'subject')
self._body = _get_node(value, 'body')
self._html = _get_node(value, 'html')
def send(self, *args, **kwargs):
"""Render email with the current context and send it"""
# Prepare context
context = Context(self.context)
context.template = self._template
# Assume the subject may be set manually.
if self._subject is not None:
self.subject = self._subject.render(context).strip('\n\r')
# Same for body.
if self._body is not None:
self.body = self._body.render(context).strip('\n\r')
# The html block is optional, and it also may be set manually.
if self._html is not None:
html = self._html.render(context).strip('\n\r')
if html:
if not self.body:
# This is html only message.
self.body = html
self.content_subtype = 'html'
else:
# Add alternative content.
self.attach_alternative(html, 'text/html')
return super(EmailMessage, self).send(*args, **kwargs)
def __getstate__(self):
"""
Exclude BlockNode and Template objects from pickling, b/c they can't
be pickled.
"""
return dict((k, v) for k, v in self.__dict__.iteritems()
if not k in ('_body', '_html', '_subject', '_template'))
def __setstate__(self, state):
"""
Use the template_name setter after unpickling so the orignal values of
_body, _html, _subject and _template will be restored.
"""
self.__dict__ = state
self.template_name = self._template_name
def send_mail(template_name, context, from_email, recipient_list,
fail_silently=False, auth_user=None, auth_password=None,
connection=None, bcc=None, attachment=None, attachment_info=None):
"""
Easy wrapper for sending a single message to a recipient list using
django template system.
All members of the recipient list will see the other recipients in
the 'To' field.
If auth_user is None, the EMAIL_HOST_USER setting is used.
If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
"""
connection = connection or mail.get_connection(username=auth_user,
password=auth_password,
fail_silently=fail_silently)
email = EmailMessage(template_name, context, None, None, from_email,
recipient_list, connection=connection, bcc=bcc)
if attachment:
if attachment_info:
email.attach(attachment_info['filename'],
attachment_info['content'], attachment_info['mimetype'])
else:
email.attach_file(attachment)
return email.send()