Chapter 13 ■ SMtp
249
connection = smtplib.SMTP(server)
connection.sendmail(fromaddr, toaddrs, message)
connection.quit()
s = '' if len(toaddrs) == 1 else 's'
print("Message sent to {} recipient{}".format(len(toaddrs), s))
if name == 'main':
main()
This program is quite simple because it uses a very powerful and general function from inside the Python
Standard Library. It starts by generating a simple message from the user’s command-line arguments (for details on
generating fancier messages that contain elements beyond simple plain text, see Chapter 12). Then it creates an
smtplib.SMTP object that connects to the specified server. Finally, all that’s required is a call to sendmail(). If that
returns successfully, then you know that the e-mail server accepted the message without error.
As mentioned previously in this chapter, you can see that the idea of who receives the message—the “envelope
recipient”—is, down at this level, separate from the actual text of the message. This particular program writes a To
header that happens to contain the same addresses to which it is sending the message; but the To header is just a
piece of text, and it could instead say anything else. (Whether that “anything else” would be willingly displayed by the
recipient’s e-mail client or cause a server along the way to discard the message as spam is another question!)
If you run the program from inside of the book’s network playground, it should successfully be able to connect
like this:
$ python3 simple.py mail.example.com [email protected] [email protected]
Message successfully sent to 1 recipient
Thanks to the hard work that the authors of the Python Standard Library have put into the sendmail() method,
it might be the only SMTP call you ever need! But to understand the steps that it is taking under the hood to get your
message delivered, let’s delve into more detail about how SMTP works.
Error Handling and Conversation Debugging
There are several different exceptions that might be raised while you’re programming with smtplib. They are:
• socket.gaierror for errors looking up address information
• socket.error for general network and communication problems
• socket.herror for other addressing errors
• smtplib.SMTPException or a subclass of it for SMTP conversation problems
The first three errors were covered in more detail in Chapter 3; they are raised in the operating system’s TCP
stack, detected and raised as exceptions by Python’s networking code, and passed straight through the smtplib
module and up to your program. However, as long as the underlying TCP socket works, all problems that actually
involve the SMTP e-mail conversation will result in an smtplib.SMTPException.
The smtplib module also provides a way to get a series of detailed messages about the steps it takes to send an
e-mail. To enable that level of detail, you can call the following option:
connection.set_debuglevel(1)
With this option, you should be able to track down any problems. Take a look at Listing 13-2 for a sample program
that provides basic error handling and debugging.