from application import app, mail
from threading import Thread
from flask.ext.mail import Message
__all__ = ['send_email', 'send_bulk_email', 'create_email']
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_bulk_async_email(app, emails):
with app.app_context():
with mail.connect() as conn:
for email in emails:
conn.send(email)
def create_email(subject, recipients, text_body, html_body, sender=('My Company', '[email protected]')):
email = Message(subject, sender=sender, recipients=recipients)
email.body = text_body
email.html = html_body
return email
def send_email(email):
thr = Thread(target=send_async_email, args=[app, email])
thr.start()
def send_bulk_email(emails):
thr = Thread(target=send_bulk_async_email, args=[app, emails])
thr.start()
The first two functions are used internally as the threaded function calls. The create_email function is used to generate Message objects, which are then passed back to the send_email or send_bulk_email function dependent on whether there is a singular or multiple emails, respectively.
I currently think merging the singular and multiple send functions would be overkill, and remove some of the readability, however I am also open to feedback on that opinion.
-
\$\begingroup\$ What "mail utility class"? All I see is a bunch of related functions. \$\endgroup\$200_success– 200_success2016年07月21日 07:11:13 +00:00Commented Jul 21, 2016 at 7:11
-
\$\begingroup\$ In my application, i have a utils folder separate from my models and views. You're right though, this is not a class. I'm not sure what the appropriate name is for a group of function desgined to provide related functionality is. A package? \$\endgroup\$Tex Andersen– Tex Andersen2016年07月21日 07:13:27 +00:00Commented Jul 21, 2016 at 7:13
1 Answer 1
I'd unify both functions and only have the bulk/multiple-emails version because the single case is basically a specialisation of the general case and the slight bit more work is unlikely to be noticeable (unless I missed some other technical reason why this isn't feasible).
Btw. the with
can be nested on a single line, i.e.:
def send_bulk_async_email(app, emails):
with app.app_context(), mail.connect() as conn:
for email in emails:
conn.send(email)
The default value for the sender on create_email
sounds like it
doesn't belong there and should rather be passed in like the rest,
perhaps store it in a configuration file anyway.
For spawning the threads also consider making it a bit more flexible by allowing an optional parameter for the thread creation, e.g. to use a thread pool instead of spawning an unlimited number of threads like done here.