Foundations of Python Network Programming

(WallPaper) #1
Chapter 12 ■ Building and parsing e-Mail

227

If you were to build an e-mail message using the old Message class instead of EmailMessage, you would see that
several of these headers would be missing. Instead of specifying a transfer encoding, Multipurpose Internet Mail
Extensions (MIME) version, and content type, old-fashioned e-mail messages like the one in Listing 12-1 simply omit
these headers and trust that e-mail clients will assume the traditional defaults. But the modern EmailMessage builder
is more careful to specify explicit values to ensure the highest level of interoperability possible with modern tools.
Header names, as stated before, are case insensitive. So conforming e-mail clients will make no distinction
between the meaning of Message-Id in Listing 12-1 and Message-ID (with a capital D instead) in the generated e-mail.
You can give the formatdate() function a specific Python datetime to display if you do not want it to use the
current date and time, and you can also choose to have it use Greenwich Mean Time (GMT) instead of the local time
zone. See Python’s documentation for details.
Be warned that the unique Message-ID is constructed from several pieces of information that you might not want
disclosed if you are in a very high-security situation: the exact time and date and millisecond of your call to
make_msgid(), the process ID of this invocation of your Python script, and even your current hostname if you fail to
provide an alternative with the optional domain= keyword. Implement an alternative unique-id solution (perhaps
calling upon an industrial-strength universally unique identifier [UUID] algorithm) if you want to avoid disclosing any
of these pieces of information.
Finally, note that even though the text is not officially in conformance with transmission as an email—the
triple-quoted string constant has no terminal line ending in order to save vertical space in the script—the combination
of set_content() and as_bytes() ensured that the e-mail message was properly terminated with a newline.


Adding HTML and Multimedia


Many ad-hoc mechanisms were invented in the early days to carry binary data across the 7-bit ASCII world of e-mail,
but it was the MIME standard that established an interoperable and extensible mechanism for non-ASCII payloads.
MIME allows the Content-Type e-mail header to specify a boundary string that splits the e-mail into smaller message
parts whenever it appears on a line with two hyphens in front of it. Each part can have its own headers and therefore
its own content type and encoding. If a part goes so far as to specify its own boundary string, then parts can even be
made up of further subparts, creating a hierarchy.
The Python email module does provide low-level support for building a MIME message out of whatever parts
and subparts you wish. Simply build several email.message.MIMEPart objects—each one can be given headers and a
body, using the same interface as an EmailMessage—then attach() them to their parent part or message:


my_message.attach(part1)
my_message.attach(part2)
...


However, you should only resort to manual assembly if you are working to reproduce some particular message
structure exactly, which is demanded by your application or project specifications. In most situations, you can simply
create an EmailMessage (as in Listing 12-2) and call, in order, the following four methods to build your result:


•    set_content() should be called first to install the main message body.

•    add_related() can then be called zero or more times to supplement the main content with
other resources it will need to render. Most often, you will use this when your main content is
HTML and needs images, CSS style sheets, and JavaScript files to render correctly in an e-mail
client that supports rich content. Each related resource should have a Content-Id (cid) by
which the main HTML document can reference it in hyperlinks.
Free download pdf