Foundations of Python Network Programming

(WallPaper) #1
Chapter 13 ■ SMtp

255

Because only a minority of e-mail servers on the Internet today supports TLS, an e-mail program should not,
in general, treat its absence as an error. Many TLS-aware SMTP clients will use TLS if available but will fall back on
standard, unsecured transmission otherwise. This is known as opportunistic encryption, and it is less secure than
forcing all communications to be encrypted, but it protects messages when the capability is present.
Second, sometimes a remote server claims to be TLS aware but then fails to properly establish a TLS connection.
This is often due to a misconfiguration on the server’s end. To be as robust as possible, you may wish to retry a failed
encrypted transmission to such a server over a new connection that you do not even try to encrypt.
Third, there is the situation where you cannot completely authenticate the remote server. Again, for a complete
discussion of peer validation, see Chapter 6. If your security policy dictates that you must exchange e-mail only with
trusted servers, then lack of authentication is clearly a problem warranting an error message.
Listing 13-5 acts as a TLS-capable, general-purpose client. It will connect to a server and use TLS if it can;
otherwise, it will fall back and send the message as usual. It will die with an error if the attempt to start TLS fails while
talking to an ostensibly capable server.


Listing 13-5. Using TLS Opportunistically


#!/usr/bin/env python3


Foundations of Python Network Programming, Third Edition


https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter13/tls.py


import sys, smtplib, socket, ssl


message_template = """To: {}
From: {}
Subject: Test Message from simple.py


Hello,


This is a test message sent to you from the tls.py program
in Foundations of Python Network Programming.
"""


def main():
if len(sys.argv) < 4:
name = sys.argv[0]
print("Syntax: {} server fromaddr toaddr [toaddr...]".format(name))
sys.exit(2)


server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:]
message = message_template.format(', '.join(toaddrs), fromaddr)


try:
connection = smtplib.SMTP(server)
send_message_securely(connection, fromaddr, toaddrs, message)
except (socket.gaierror, socket.error, socket.herror,
smtplib.SMTPException) as e:
print("Your message may not have been sent!")
print(e)
sys.exit(1)
else:
s = '' if len(toaddrs) == 1 else 's'
print("Message sent to {} recipient{}".format(len(toaddrs), s))
connection.quit()

Free download pdf