Recipe13.5.Sending HTML Mail


Recipe 13.5. Sending HTML Mail

Credit: Art Gillespie

Problem

You need to send HTML mail and accompany it with a plain text version of the message's contents, so that the email message is also readable by MUAs that are not HTML-capable.

Solution

Although the modern Python way to perform any mail manipulation is with the standard Python library email package, the functionality we need for this recipe is also supplied by the MimeWriter and mimetools modules (which are also in the Python Standard Library). We can easily code a function that just accesses and uses that functionality:

def createhtmlmail(subject, html, text=None):     " Create a mime-message that will render as HTML or text, as appropriate"     import MimeWriter, mimetools, cStringIO     if text is None:         # Produce an approximate textual rendering of the HTML string,         # unless you have been given a better version as an argument         import htmllib, formatter         textout = cStringIO.StringIO( )         formtext = formatter.AbstractFormatter(formatter.DumbWriter(textout))         parser = htmllib.HTMLParser(formtext)         parser.feed(html)         parser.close( )         text = textout.getvalue( )         del textout, formtext, parser     out = cStringIO.StringIO( )              # output buffer for our message     htmlin = cStringIO.StringIO(html)    # input buffer for the HTML     txtin = cStringIO.StringIO(text)     # input buffer for the plain text     writer = MimeWriter.MimeWriter(out)     # Set up some basic headers. Place subject here because smtplib.sendmail     # expects it to be in the message, as relevant RFCs prescribe.     writer.addheader("Subject", subject)     writer.addheader("MIME-Version", "1.0")     # Start the multipart section of the message.  Multipart/alternative seems     # to work better on some MUAs than multipart/mixed.     writer.startmultipartbody("alternative")     writer.flushheaders( )     # the plain-text section: just copied through, assuming iso-8859-1     subpart = writer.nextpart( )     pout = subpart.startbody("text/plain", [("charset", 'iso-8859-1')])     pout.write(txtin.read( ))     txtin.close( )     # the HTML subpart of the message: quoted-printable, just in case     subpart = writer.nextpart( )     subpart.addheader("Content-Transfer-Encoding", "quoted-printable")     pout = subpart.startbody("text/html", [("charset", 'us-ascii')])     mimetools.encode(htmlin, pout, 'quoted-printable')     htmlin.close( )     # You're done; close your writer and return the message as a string     writer.lastpart( )     msg = out.getvalue( )     out.close( )     return msg

Discussion

This recipe's module is completed in the usual style with a few lines to ensure that, when run as a script, it runs a self-test by composing and sending a sample HTML mail:

if _ _name_ _=="_ _main_ _":     import smtplib     f = open("newsletter.html", 'r')     html = f.read( )     f.close( )     try:         f = open("newsletter.txt", 'r')         text = f.read( )     except IOError:         text = None     subject = "Today's Newsletter!"     message = createhtmlmail(subject, html, text)     server = smtplib.SMTP("localhost")     server.sendmail('agillesp@i-noSPAMSUCKS.com',         'agillesp@i-noSPAMSUCKS.com', message)     server.quit( )

Sending HTML mail is a popular concept, and (as long as you avoid sending it to newsgroups and open mailing lists) there's no reason your Python scripts shouldn't do it. When you do send HTML mail, never forget to embed a text-only version of your message along with the HTML version. Lots of folks still prefer character-mode mail readers (technically known as MUAs), and it makes no sense to alienate those users by sending mail that they can't conveniently read. This recipe shows how easy Python makes the task of sending an email in both HTML and text forms.

Ideally, your input will be a properly formatted text version of the message, as well as the HTML version. But, if you don't have such nice textual input, you can still prepare a text version on the fly starting from the HTML version; one way to prepare such text is shown in the recipe. Remember that htmllib has some limitations, so you may want to use alternative approaches, such as saving the HTML string to disk and then using:

text = os.popen('lynx -dump %s' % tempfile).read( )

or whatever works best for you. Alternatively, if all you have as input is plain text (following some specific conventions, such as empty lines to mark paragraphs and underlines for emphasis), you can parse the text and throw together some HTML markup on the fly.

The emails generated by this code have been successfully read on Outlook 2000, Eudora 4.2, Hotmail, and Netscape Mail. It's likely that they will work in other HTML-capable MUAs as well. Mutt has been used to test the acceptance of messages generated by this recipe in text-only MUAs. Again, other such MUAs can be expected to work just as acceptably.

See Also

Recipe 13.6 shows how the email package in the Python Standard Library can also be used to compose a MIME multipart message; documentation in the Library Reference and Python in a Nutshell about the standard library package email, as well as modules mimetools, MimeWriter, htmllib, formatter, cStringIO, and smtplib; Henry Minsky's article about MIME (http://www.arsdigita.com/asj/mime/) for information on various issues related to sending HTML mail.



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