summaryrefslogtreecommitdiff
path: root/ssmain/email.py
blob: c9d80a00052b84ee6ac7117f4a0432ec961ec225 (plain)
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
1#    Society Self-Service
2#    Copyright © 2018-2019  Yingtong Li (RunasSudo)
3#
4#    This program is free software: you can redistribute it and/or modify
5#    it under the terms of the GNU Affero General Public License as published by
6#    the Free Software Foundation, either version 3 of the License, or
7#    (at your option) any later version.
8#
9#    This program is distributed in the hope that it will be useful,
10#    but WITHOUT ANY WARRANTY; without even the implied warranty of
11#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12#    GNU Affero General Public License for more details.
13#
14#    You should have received a copy of the GNU Affero General Public License
15#    along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17import boto3
18from botocore.exceptions import ClientError
19import premailer
20
21from django.conf import settings
22from django.template import loader
23from jinja2 import Markup
24
25import logging
26import markdown
27
28# Debugging
29import subprocess
30import tempfile
31import time
32
33class Emailer:
34	def __init__(self):
35		self.client = boto3.client('ses', aws_access_key_id=settings.AWS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET, region_name=settings.AWS_REGION)
36		self.template = loader.get_template('ssmain/email/rendered.html')
37	
38	def markdown(self, x):
39		return markdown.markdown(x, extensions=['mdx_urlize', 'fenced_code'])
40	
41	def boto3_send(self, *args, **kwargs):
42		for i in range(0, 10):
43			try:
44				self.client.send_email(*args, **kwargs)
45				return
46			except ClientError as e:
47				if e['Error']['Code'] == 'Throttling' and e['Error']['Message'] == 'Maximum sending rate exceeded.':
48					wait_time = max(10*(2**i), 5000)
49					#self.stdout.write(self.style.NOTICE('Reached maximum sending rate, waiting {} ms'.format(wait_time)))
50					time.sleep(wait_time/1000)
51				else:
52					raise e
53		raise Exception('Reached maximum number of retries')
54	
55	def send_raw_mail(self, recipients, subject, content_txt, content_html):
56		if settings.EMAIL_DEBUG:
57			with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', suffix='.eml') as f:
58				print('Subject:' + subject + '\nContent-Type: multipart/alternative; boundary=boundary\n\n--boundary\nContent-Type: text/html; charset=utf-8\n\n' + content_html + '\n--boundary\nContent-Type: text/plain; charset=utf-8\n\n' + content_txt + '\n--boundary', file=f)
59				subprocess.run(['thunderbird', f.name])
60				time.sleep(5)
61		else:
62			self.boto3_send(
63				Destination={
64					'ToAddresses': recipients,
65				},
66				Message={
67					'Body': {
68						'Html': {
69							'Charset': 'utf-8',
70							'Data': content_html,
71						},
72						'Text': {
73							'Charset': 'utf-8',
74							'Data': content_txt,
75						},
76					},
77					'Subject': {
78						'Charset': 'utf-8',
79						'Data': subject,
80					},
81				},
82				Source='{} <{}>'.format(settings.ORG_NAME, settings.AWS_SENDER_EMAIL),
83			)
84	
85	def render_mail(self, template_loc, params={}):
86		params['baseurl'] = 'https://' + settings.ALLOWED_HOSTS[0]
87		
88		template = loader.get_template(template_loc)
89		content_txt = template.render(params)
90		
91		content_markdown = self.markdown(content_txt)
92		content_html = self.template.render({'email_content': Markup(content_markdown)})
93		
94		content_html = premailer.Premailer(content_html, cssutils_logging_level=logging.ERROR, strip_important=False).transform()
95		
96		return content_txt, content_html
97	
98	def send_mail(self, recipients, subject, template_loc, params):
99		content_txt, content_html = self.render_mail(template_loc, params)
100		self.send_raw_mail(recipients, subject, content_txt, content_html)
Contact (issues, pull requests, etc.) at git@yingtongli.me. Generated by cgit.