Sending Mail

Twisted contains many ways of sending email, but the simplest is sendmail. Intended as a near drop-in replacement of smtplib.SMTP‘s sendmail method, it provides the ability to send email over SMTP/ESMTP with minimal fuss or configuration.

Knowledge of Twisted’s Deferreds is required for making full use of this document.

Sending an Email over SMTP

Although insecure, some email systems still use plain SMTP for sending email. Plain SMTP has no authentication, no transport security (emails are transmitted in plain text), and should not be done over untrusted networks.

sendmail‘s positional arguments are, in order:

  • The SMTP/ESMTP server you are sending the message to
  • The email address you are sending from
  • A list of email addresses you are sending to
  • The message.

The following example shows these in action.

sendmail_smtp.py

from __future__ import print_function

from twisted.mail.smtp import sendmail
from twisted.internet.task import react

def main(reactor):
    d = sendmail("myinsecuremailserver.example.com",
                 "alice@example.com",
                 ["bob@gmail.com", "charlie@gmail.com"],
                 "This is my super awesome email, sent with Twisted!")

    d.addBoth(print)
    return d

react(main)

Assuming that the values in it were replaced with real emails and a real SMTP server, it would send an email to the two addresses specified and print the return status.

Sending an Email over ESMTP

Extended SMTP (ESMTP) is an improved version of SMTP, and is used by most modern mail servers. Unlike SMTP, ESMTP supports authentication and transport security (emails are encrypted in transit). If you wish to send mail through services like GMail/Google Apps or Outlook.com/Office 365, you will have to use ESMTP.

Using ESMTP requires more options – usually the default port of 25 is not open, so you must find out your email provider’s TLS-enabled ESMTP port. It also allows the use of authentication via a username and password.

The following example shows part of the ESMTP functionality of sendmail.

sendmail_gmail.py

from __future__ import print_function

from twisted.mail.smtp import sendmail
from twisted.internet.task import react

def main(reactor):

    d = sendmail("smtp.gmail.com",
                 "alice@gmail.com",
                 ["bob@gmail.com", "charlie@gmail.com"],
                 "This is my super awesome email, sent with Twisted!",
                 port=587, username="alice@gmail.com", password="*********")

    d.addBoth(print)
    return d

react(main)

Assuming you own the account alice@gmail.com, this would send an email to both bob@gmail.com and charlie@gmail.com, and print out something like the following (formatted for clarity):

(2, [('bob@gmail.com', 250, '2.1.5 OK hz13sm11691456pac.6 - gsmtp'),
     ('charlie@gmail.com', 250, '2.1.5 OK hz13sm11691456pac.6 - gsmtp')])

sendmail returns a 2-tuple, containing the number of emails sent successfully (note that this is from you to the server you specified, not to the recepient – emails may still be lost between that server and the recepient) and a list of statuses of the sent mail. Each status is a 3-tuple containing the address it was sent to, the SMTP status code, and the server response.

Sending Complex Emails

Sometimes you want to send more complicated emails – ones with headers, or with attachments. sendmail supports using Python’s email.Message, which lets you make complex emails:

sendmail_message.py

from __future__ import print_function

from twisted.mail.smtp import sendmail
from twisted.internet.task import react

from email.mime.text import MIMEText

def main(reactor):
    me = "alice@gmail.com"
    to = ["bob@gmail.com", "charlie@gmail.com"]

    message = MIMEText("This is my super awesome email, sent with Twisted!")
    message["Subject"] = "Twisted is great!"
    message["From"] = me
    message["To"] = ", ".join(to)

    d = sendmail("smtp.gmail.com", me, to, message,
                 port=587, username=me, password="*********",
                 requireAuthentication=True,
                 requireTransportSecurity=True)

    d.addBoth(print)
    return d

react(main)

For more information on how to use Message, please see the module’s Python docs.

Enforcing Transport Security

To prevent downgrade attacks, you can pass requireTransportSecurity=True to sendmail. This means that your emails will not be transmitted in plain text.

For example:

sendmail("smtp.gmail.com", me, to, message,
         port=587, username=me, password="*********",
         requireTransportSecurity=True)

Conclusion

In this document, you have seen how to:

  1. Send an email over SMTP using sendmail.
  2. Send an email over encrypted & authenticated ESMTP with sendmail.
  3. Send a “complex” email containing a subject line using the stdlib’s email.Message functionality.
  4. Enforce transport security for emails sent using sendmail.