Recipe13.6.Bundling Files in a MIME Message


Recipe 13.6. Bundling Files in a MIME Message

Credit: Matthew Dixon Cowles, Hans Fangohr, John Pywtorak

Problem

You want to create a multipart MIME (Multipurpose Internet Mail Extensions) message that includes all files in the current directory.

Solution

If you often deal with composing or parsing mail messages, or mail-like messages such as Usenet news posts, the Python Standard Library email package gives you very powerful tools to work with. Here is a module that uses email to solve the task posed in the "Problem":

#!/usr/bin/env python import base64, quopri import mimetypes, email.Generator, email.Message import cStringIO, os # sample addresses toAddr = "example@example.com" fromAddr = "example@example.com" outputFile = "dirContentsMail" def main( ):     mainMsg = email.Message.Message( )     mainMsg["To"] = toAddr     mainMsg["From"] = fromAddr     mainMsg["Subject"] = "Directory contents"     mainMsg["Mime-version"] = "1.0"     mainMsg["Content-type"] = "Multipart/mixed"     mainMsg.preamble = "Mime message\n"     mainMsg.epilogue = "" # to ensure that message ends with newline     # Get names of plain files (not subdirectories or special files)     fileNames = [f for f in os.listdir(os.curdir) if os.path.isfile(f)]     for fileName in fileNames:         contentType, ignored = mimetypes.guess_type(fileName)         if contentType is None:     # If no guess, use generic opaque type             contentType = "application/octet-stream"         contentsEncoded = cStringIO.StringIO( )         f = open(fileName, "rb")         mainType = contentType[:contentType.find("/")]         if mainType=="text":             cte = "quoted-printable"             quopri.encode(f, contentsEncoded, 1)   # 1 to also encode tabs         else:             cte = "base64"             base64.encode(f, contentsEncoded)         f.close( )         subMsg = email.Message.Message( )         subMsg.add_header("Content-type", contentType, name=fileName)         subMsg.add_header("Content-transfer-encoding", cte)         subMsg.set_payload(contentsEncoded.getvalue( ))         contentsEncoded.close( )         mainMsg.attach(subMsg)     f = open(outputFile, "wb")     g = email.Generator.Generator(f)     g.flatten(mainMsg)     f.close( )     return None if _ _name_ _=="_ _main_ _":     main( )

Discussion

The email package makes manipulating MIME messages a snap. The Python Standard Library also offers other older modules that can serve many of the same purposes, but I suggest you look into email as an alternative to all such other modules. email requires some study because it is a very functionally rich package, but it will amply repay the time you spend studying it.

MIME is the Internet standard for sending files and non-ASCII data by email. The standard is specified in RFCs 2045-2049. A few points are especially worth keeping in mind:

  • The original specification for the format of an email (RFC 822) didn't allow for non-ASCII characters and had no provision for attaching or enclosing a file along with a text message. Therefore, not surprisingly, MIME messages are very common these days.

  • Messages that follow the MIME standard are backward compatible with ordinary RFC 822 (now RFC 2822) messages. An old mail reader (technically, an MUA) that doesn't understand the MIME specification will probably not be able to display a MIME message in a way that's useful to the user, but the message will still be legal and therefore shouldn't cause unexpected behavior.

  • An RFC 2822 message consists of a set of headers, a blank line, and a body. MIME handles attachments and other multipart documents by specifying a format for the message's body. In multipart MIME messages, the body is divided into submessages, each of which has a set of headers, a blank line, and a body. Generally, each submessage is referred to as a MIME part, and parts may nest recursively.

  • MIME parts (whether or not in a multipart message) that contain characters outside of the strict US-ASCII range are encoded as either base-64 or quoted-printable data, so that the resulting mail message contains only ordinary ASCII characters. Data can be encoded with either method, but, generally, only data that has few non-ASCII characters (basically text, possibly with a few extra characters outside of the ASCII range, such as national characters in Latin-1 and similar codes) is worth encoding as quoted-printable, because even without decoding it may be readable. If the data is essentially binary, with all bytes being equally likely, base-64 encoding is more compact.

Not surprisingly, given all of these issues, manipulating MIME messages is often considered to be a nuisance. In the old times, back before Python 2.2, the standard library's modules for dealing with MIME messages were quite useful but rather miscellaneous. In particular, putting MIME messages together and taking them apart required two distinct approaches. The email package, which was added in Python 2.2, unified and simplified these two related jobs.

See Also

Recipe 13.7 shows how the email package can be used to unpack a MIME message; documentation for the standard library modules email, mimetypes, base64, quopri, and cStringIO in the Library Reference and Python in a Nutshell.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net