8
\$\begingroup\$
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', 'info@mycompany.com.au')):
    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.

\$\endgroup\$
  • \$\begingroup\$ What "mail utility class"? All I see is a bunch of related functions. \$\endgroup\$ – 200_success Jul 21 '16 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 Jul 21 '16 at 7:13
2
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.