]> git.openstreetmap.org Git - osqa.git/blob - forum/utils/mail.py
Tries to eliminate a possible race condition when a user who is trying to ask a quest...
[osqa.git] / forum / utils / mail.py
1 import email
2 import socket
3 import os
4
5 from email.mime.multipart import MIMEMultipart
6 from email.mime.text import MIMEText
7 from email.mime.image import MIMEImage
8 from email.header import Header
9 import email.Charset
10
11 from django.core.mail import DNS_NAME
12 from smtplib import SMTP
13 from forum import settings
14 from django.template import loader, Context, Template
15 from forum.utils.html import sanitize_html
16 from forum.context import application_settings
17 from forum.utils.html2text import HTML2Text
18 from threading import Thread
19
20 def send_msg_list(msgs, sender=None):
21     if len(msgs):
22         connection = SMTP(str(settings.EMAIL_HOST), str(settings.EMAIL_PORT),
23                           local_hostname=DNS_NAME.get_fqdn())
24
25         try:
26             if (bool(settings.EMAIL_USE_TLS)):
27                 connection.ehlo()
28                 connection.starttls()
29                 connection.ehlo()
30
31             if settings.EMAIL_HOST_USER and settings.EMAIL_HOST_PASSWORD:
32                 connection.login(str(settings.EMAIL_HOST_USER), str(settings.EMAIL_HOST_PASSWORD))
33
34             if sender is None:
35                 sender = str(settings.DEFAULT_FROM_EMAIL)
36
37             for email, msg in msgs:
38                 try:
39                     connection.sendmail(sender, [email], msg)
40                 except Exception, e:
41                     pass
42             try:
43                 connection.quit()
44             except socket.sslerror:
45                 connection.close()
46         except Exception, e:
47             pass
48
49 def html2text(s, ignore_tags=(), indent_width=4, page_width=80):
50     ignore_tags = [t.lower() for t in ignore_tags]
51     parser = HTML2Text(ignore_tags, indent_width, page_width)
52     parser.feed(s)
53     parser.close()
54     parser.generate()
55     return parser.result
56
57 def named(data):
58     if isinstance(data, (tuple, list)) and len(data) == 2:
59         return '%s <%s>' % data
60
61     return str(data)
62
63 def create_msg(subject, sender, recipient, html, text, images):
64     msgRoot = MIMEMultipart('related')
65     msgRoot['Subject'] = subject
66     msgRoot['From'] = named(sender)
67     msgRoot['To'] =  named(recipient)
68     msgRoot.preamble = 'This is a multi-part message from %s.' % unicode(settings.APP_SHORT_NAME).encode('utf8')
69
70     msgAlternative = MIMEMultipart('alternative')
71     msgRoot.attach(msgAlternative)
72
73     msgAlternative.attach(MIMEText(text, _charset='utf-8'))
74     msgAlternative.attach(MIMEText(html, 'html', _charset='utf-8'))
75
76     for img in images:
77         try:
78             fp = open(img[0], 'rb')
79             msgImage = MIMEImage(fp.read())
80             fp.close()
81             msgImage.add_header('Content-ID', '<'+img[1]+'>')
82             msgRoot.attach(msgImage)
83         except:
84             pass
85
86     return msgRoot.as_string()
87
88 def send_email(subject, recipients, template, context={}, sender=None, images=[], threaded=True):
89     if sender is None:
90         sender = (unicode(settings.APP_SHORT_NAME), unicode(settings.DEFAULT_FROM_EMAIL))
91
92     if not len(images):
93         images = [(os.path.join(str(settings.UPFILES_FOLDER), os.path.basename(str(settings.APP_LOGO))), 'logo')]
94
95     context.update(application_settings(None))
96     html_body = loader.get_template(template).render(Context(context))
97     txt_body = html2text(html_body)
98
99     if isinstance(recipients, str):
100         recipients = [recipients]
101
102     msgs = []
103
104     for recipient in recipients:
105         if isinstance(recipient, str):
106             recipient_data = ('recipient', recipient)
107             recipient_context = None
108         elif isinstance(recipient, (list, tuple)) and len(recipient) == 2:
109             name, email = recipient
110             recipient_data = (name, email)
111             recipient_context = None
112         elif isinstance(recipient, (list, tuple)) and len(recipient) == 3:
113             name, email, recipient_context = recipient
114             recipient_data = (name, email)
115         else:
116             raise Exception('bad argument for recipients')
117
118         if recipient_context is not None:
119             recipient_context = Context(recipient_context)
120             msg_html = Template(html_body).render(recipient_context)
121             msg_txt = Template(txt_body).render(recipient_context)
122         else:
123             msg_html = html_body
124             msg_txt = txt_body
125
126         msg = create_msg(subject, sender, recipient_data, msg_html, msg_txt, images)
127         msgs.append((email, msg))
128
129     if threaded:
130         thread = Thread(target=send_msg_list, args=[msgs])
131         thread.setDaemon(True)
132         thread.start()
133     else:
134         send_msg_list(msgs)
135
136
137 def send_template_email(recipients, template, context):
138     t = loader.get_template(template)
139     context.update(dict(recipients=recipients, settings=settings))
140     t.render(Context(context))
141
142 def create_and_send_mail_messages(messages):
143     if not settings.EMAIL_HOST:
144         return
145
146     sender = Header(unicode(settings.APP_SHORT_NAME), 'utf-8')
147     sender.append('<%s>' % unicode(settings.DEFAULT_FROM_EMAIL))
148     sender = u'%s <%s>' % (unicode(settings.APP_SHORT_NAME), unicode(settings.DEFAULT_FROM_EMAIL))
149
150     try:
151         connection = SMTP(str(settings.EMAIL_HOST), str(settings.EMAIL_PORT),
152                           local_hostname=DNS_NAME.get_fqdn())
153
154         if (bool(settings.EMAIL_USE_TLS)):
155             connection.ehlo()
156             connection.starttls()
157             connection.ehlo()
158
159         if settings.EMAIL_HOST_USER and settings.EMAIL_HOST_PASSWORD:
160             connection.login(str(settings.EMAIL_HOST_USER), str(settings.EMAIL_HOST_PASSWORD))
161
162         if sender is None:
163             sender = str(settings.DEFAULT_FROM_EMAIL)
164
165         for recipient, subject, html, text, media in messages:
166             msgRoot = MIMEMultipart('related')
167
168             msgRoot['Subject'] = Header(subject, 'utf-8')
169             msgRoot['From'] = sender
170
171             to = Header(recipient.username, 'utf-8')
172             to.append('<%s>' % recipient.email)
173             msgRoot['To'] = to
174
175             msgRoot.preamble = 'This is a multi-part message from %s.' % unicode(settings.APP_SHORT_NAME).encode('utf8')
176
177             msgAlternative = MIMEMultipart('alternative')
178             msgRoot.attach(msgAlternative)
179
180             msgAlternative.attach(MIMEText(text.encode('utf-8'), _charset='utf-8'))
181             msgAlternative.attach(MIMEText(html.encode('utf-8'), 'html', _charset='utf-8'))
182
183             for alias, location in media.items():
184                 fp = open(location, 'rb')
185                 msgImage = MIMEImage(fp.read())
186                 fp.close()
187                 msgImage.add_header('Content-ID', '<'+alias+'>')
188                 msgRoot.attach(msgImage)
189
190             try:
191                 connection.sendmail(sender, [recipient.email], msgRoot.as_string())
192             except Exception, e:
193                 pass
194
195         try:
196             connection.quit()
197         except socket.sslerror:
198             connection.close()
199     except Exception, e:
200         pass