Coverage for portality/app_email.py: 33%
69 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-08-04 15:38 +0100
« prev ^ index » next coverage.py v6.4.2, created at 2022-08-04 15:38 +0100
1# ~~Email:Library~~
2from flask import render_template, flash
3from flask_mail import Mail, Message, Attachment
4from portality.core import app
6import uuid
7import markdown
10class EmailException(Exception):
11 pass
14def send_markdown_mail(to, fro, subject, template_name=None, bcc=None, files=None, msg_body=None, markdown_template_name=None, **template_params):
15 html_body = None
16 if markdown_template_name:
17 try:
18 markdown_body = render_template(markdown_template_name, **template_params)
19 except:
20 with app.test_request_context():
21 markdown_body = render_template(markdown_template_name, **template_params)
23 md = markdown.Markdown()
24 html_body = md.convert(markdown_body)
26 send_mail(to, fro, subject, template_name=template_name, bcc=bcc, files=files, msg_body=msg_body, html_body=html_body, **template_params)
28# Flask-Mail version of email service from util.py
29def send_mail(to, fro, subject, template_name=None, bcc=None, files=None, msg_body=None, html_body=None, **template_params):
30 """
31 ~~-> Email:ExternalService~~
32 ~~-> FlaskMail:Library~~
33 :param to:
34 :param fro:
35 :param subject:
36 :param template_name:
37 :param bcc:
38 :param files:
39 :param msg_body:
40 :param template_params:
41 :return:
42 """
43 bcc = [] if bcc is None else bcc
44 files = [] if files is None else files
46 # ensure that email isn't sent if it is disabled
47 if not app.config.get("ENABLE_EMAIL", False):
48 app.logger.info("Email template {0} called to send, but email has been disabled.\nto:{1}\tsubject:{2}".format(template_name, to, subject))
49 return
51 assert type(to) == list
52 assert type(files) == list
53 if bcc and not isinstance(bcc, list):
54 bcc = [bcc]
56 to_is_invalid = True
57 for t in to:
58 if t:
59 to_is_invalid = False
60 # a list of None, None, None or even just a [None] is no good!
62 if to_is_invalid:
63 magic = str(uuid.uuid1())
64 app.logger.error('Bad To list while trying to send email with subject \"{0}\". Magic num for log grep {1}'.format(subject, magic))
65 flash("Invalid email address - no email specified at all. Trying to send email with subject \"{0}\". Magic number to help identify error: {1}".format(subject, magic), 'error')
66 return
68 if app.config.get('CC_ALL_EMAILS_TO', None) is not None:
69 bcc.append(app.config.get('CC_ALL_EMAILS_TO'))
71 # Get the body text from the msg_body parameter (for a contact form),
72 # or render from a template.
73 # TODO: This could also find and render an HTML template if present
74 if msg_body:
75 plaintext_body = msg_body
76 else:
77 try:
78 plaintext_body = render_template(template_name, **template_params)
79 except:
80 with app.test_request_context():
81 plaintext_body = render_template(template_name, **template_params)
83 # strip all the leading and trailing whitespace from the body, which the templates
84 # leave lying around
85 plaintext_body = plaintext_body.strip()
87 # create a message
88 msg = Message(subject=subject,
89 recipients=to,
90 body=plaintext_body,
91 html=html_body,
92 sender=fro,
93 cc=None,
94 bcc=bcc,
95 attachments=files,
96 reply_to=None,
97 date=None,
98 charset=None,
99 extra_headers=None
100 )
102 try:
103 mail = Mail(app)
104 with app.app_context():
105 mail.send(msg)
106 app.logger.info("Email template {0} sent.\nto:{1}\tsubject:{2}".format(template_name, to, subject))
107 except Exception as e:
108 raise EmailException(e)
111def make_attachment(filename, content_type, data, disposition=None, headers=None):
112 """
113 Provide a function which can make attachments, insulating the caller from the flask-mail
114 underlying implementation.
116 :param filename:
117 :param content_type:
118 :param data:
119 :param disposition:
120 :param headers:
121 :return:
122 """
123 return Attachment(filename, content_type, data, disposition, headers)
126def email_archive(data_dir, archv_name):
127 """
128 Compress and email the reports to the specified email address.
129 :param data_dir: Directory containing the reports
130 :param archv_name: Filename for the archive and resulting email attachment
131 """
132 import shutil, os
134 email_to = app.config.get('REPORTS_EMAIL_TO', ['helpdesk@doaj.org'])
135 email_from = app.config.get('SYSTEM_EMAIL_FROM', 'helpdesk@doaj.org')
136 email_sub = app.config.get('SERVICE_NAME', '') + ' - generated {0}'.format(archv_name)
137 msg = "Attached: {0}.zip\n".format(archv_name)
139 # Create an archive of the reports
140 archv = shutil.make_archive(archv_name, "zip", root_dir=data_dir)
142 # Read the archive to create an attachment, send it with the app email
143 with open(archv, 'rb') as f:
144 dat = f.read()
145 attach = [make_attachment(filename=archv_name, content_type='application/zip', data=dat)]
146 send_mail(to=email_to, fro=email_from, subject=email_sub, msg_body=msg, files=attach)
148 # Clean up the archive
149 os.remove(archv)