-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutils.py
168 lines (133 loc) · 5.44 KB
/
utils.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
165
166
167
168
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.files import File
from django.utils.encoding import force_str
from post_office import cache
from .models import Email, PRIORITY, STATUS, EmailTemplate, Attachment
from .settings import get_default_priority
from .validators import validate_email_with_name
def send_mail(subject, message, from_email, recipient_list, html_message='',
scheduled_time=None, headers=None, priority=PRIORITY.medium):
"""
Add a new message to the mail queue. This is a replacement for Django's
``send_mail`` core email method.
"""
subject = force_str(subject)
status = None if priority == PRIORITY.now else STATUS.queued
emails = [
Email.objects.create(
from_email=from_email, to=address, subject=subject,
message=message, html_message=html_message, status=status,
headers=headers, priority=priority, scheduled_time=scheduled_time
) for address in recipient_list
]
if priority == PRIORITY.now:
for email in emails:
email.dispatch()
return emails
def get_email_template(name, language=''):
"""
Function that returns an email template instance, from cache or DB.
"""
use_cache = getattr(settings, 'POST_OFFICE_CACHE', True)
if use_cache:
use_cache = getattr(settings, 'POST_OFFICE_TEMPLATE_CACHE', True)
if not use_cache:
return EmailTemplate.objects.get(name=name, language=language)
else:
composite_name = '%s:%s' % (name, language)
email_template = cache.get(composite_name)
if email_template is None:
email_template = EmailTemplate.objects.get(name=name, language=language)
cache.set(composite_name, email_template)
return email_template
def split_emails(emails, split_count=1):
# Group emails into X sublists
# taken from http://www.garyrobinson.net/2008/04/splitting-a-pyt.html
# Strange bug, only return 100 email if we do not evaluate the list
if list(emails):
return [emails[i::split_count] for i in range(split_count)]
return []
def create_attachments(attachment_files):
"""
Create Attachment instances from files
attachment_files is a dict of:
* Key - the filename to be used for the attachment.
* Value - file-like object, or a filename to open OR a dict of {'file': file-like-object, 'mimetype': string}
Returns a list of Attachment objects
"""
attachments = []
for filename, filedata in attachment_files.items():
if isinstance(filedata, dict):
content = filedata.get('file', None)
mimetype = filedata.get('mimetype', None)
headers = filedata.get('headers', None)
else:
content = filedata
mimetype = None
headers = None
opened_file = None
if isinstance(content, str):
# `content` is a filename - try to open the file
opened_file = open(content, 'rb')
content = File(opened_file)
attachment = Attachment()
if mimetype:
attachment.mimetype = mimetype
attachment.headers = headers
attachment.name = filename
attachment.file.save(filename, content=content, save=True)
attachments.append(attachment)
if opened_file is not None:
opened_file.close()
return attachments
def parse_priority(priority):
if priority is None:
priority = get_default_priority()
# If priority is given as a string, returns the enum representation
if isinstance(priority, str):
priority = getattr(PRIORITY, priority, None)
if priority is None:
raise ValueError('Invalid priority, must be one of: %s' %
', '.join(PRIORITY._fields))
return priority
def parse_emails(emails):
"""
A function that returns a list of valid email addresses.
This function will also convert a single email address into
a list of email addresses.
None value is also converted into an empty list.
"""
if isinstance(emails, str):
emails = [emails]
elif emails is None:
emails = []
for email in emails:
try:
validate_email_with_name(email)
except ValidationError:
raise ValidationError('%s is not a valid email address' % email)
return emails
def cleanup_expired_mails(cutoff_date, delete_attachments=True, batch_size=1000):
"""
Delete all emails before the given cutoff date.
Optionally also delete pending attachments.
Return the number of deleted emails and attachments.
"""
expired_emails_ids = Email.objects.filter(created__lt=cutoff_date).values_list('id', flat=True)
email_id_batches = split_emails(expired_emails_ids, batch_size)
total_deleted_emails = 0
for email_ids in email_id_batches:
# Delete email and incr total_deleted_emails counter
_, deleted_data = Email.objects.filter(id__in=email_ids).delete()
if deleted_data:
total_deleted_emails += deleted_data['post_office.Email']
if delete_attachments:
attachments = Attachment.objects.filter(emails=None)
for attachment in attachments:
# Delete the actual file
attachment.file.delete()
attachments_count, _ = attachments.delete()
else:
attachments_count = 0
return total_deleted_emails, attachments_count