Sending emails asynchronously using Twisted – Part 1

  • Using ‘smtplib‘ module

It is very easy to send emails using ‘smtplib‘ module of python. Check following recipe.

#!/usr/bin/env python2.7
__author__ = 'Rohit Chormale'


from smtplib import SMTP


# enter email content
CONTENT = """
"""
# enter email subject
SUBJECT = """
"""
# enter recipients
TO_EMAILS = ["", ""]
# enter sender's emails
FROM_EMAIL = ""
# enter username of your email account
USERNAME = ""
# enter password of your email account
PASSWORD = ""
# enter smtp host of your email provider
SMTP_HOST = ""
# enter smtp host of your email provider
SMTP_PORT = 0


mailer = SMTP(SMTP_HOST, SMTP_PORT)
mailer.starttls()
mailer.login(USERNAME, PASSWORD)
mailer.sendmail(FROM_EMAIL, TO_EMAILS, CONTENT)
mailer.quit()

But ‘smtplib’ module sends emails synchronously. So code execution is blocked until email is sent. To overcome this, lets try to send email asynchornously.

  • Using Twisted

For this tutorial we are going to use Twisted framework. Twisted is event-driven networking engine. It uses reactor-pattern. Twisted uses deferred objects to address waiting IOs. Deferred is more like subset of promises. Check following recipe to send asynchronously MIME message using Twisted.

#!/usr/bin/env python2.7
__author__ = 'Rohit Chormale'


from StringIO import StringIO
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import formatdate
from email.header import Header

from twisted.mail.smtp import ESMTPSenderFactory
from twisted.internet import reactor, defer
from twisted.internet.ssl import ClientContextFactory

# enter email content
CONTENT = """
"""
# enter email subject
SUBJECT = ""
# enter recipients
TO_EMAILS = ["", ""]
# enter sender email
FROM_EMAIL = ""
# enter username of your email account
USERNAME = ""
# enter password of your email account
PASSWORD = ""
# enter smtp host of your email provider
SMTP_HOST = ""
# enter smtp port of your email provider
SMTP_PORT = 0


def success(result):
    print 'Email sent successfully'
    print result
    reactor.stop()


def failure(error):
    print 'Failed to send email'
    print error
    reactor.stop()


def send_email():
    mime_text = MIMEText(CONTENT, 'html', 'utf-8')
    mime_msg = MIMEMultipart('alternative')
    mime_msg['Subject'] = "%s" % Header(SUBJECT, 'utf-8')
    mime_msg['To'] = ",".join(TO_EMAILS)
    mime_msg['From'] = FROM_EMAIL
    mime_msg['Date'] = formatdate(localtime=True)
    mime_msg.attach(mime_text)
    mime_msg = StringIO(mime_msg.as_string())
    df = defer.Deferred()
    f = ESMTPSenderFactory(USERNAME, PASSWORD, FROM_EMAIL, TO_EMAILS, mime_msg,
                           df, retries=2, contextFactory=ClientContextFactory(), requireTransportSecurity=True)
    reactor.connectTCP(SMTP_HOST, SMTP_PORT, f)
    return df


def main():
    df = send_email()
    df.addCallback(success)
    df.addErrback(failure)


reactor.callLater(1, main)


if __name__ == '__main__':
    reactor.run()

 

 

About Rohit Chormale

I am software engineer from Hyderabad, India with primary interests in distributed systems. In my leisure time, I love to read technical papers and hacking emacs. View all posts by Rohit Chormale

Leave a Reply

Your email address will not be published. Required fields are marked *