I l@ve RuBoard |
10.9 Sending HTML MailCredit: Art Gillespie 10.9.1 ProblemYou need to send HTML mail and embed a message version in plain text, so that the message is also readable by MUAs that are not HTML-capable. 10.9.2 SolutionThe key functionality is supplied by the MimeWriter and mimetools modules: def createhtmlmail(subjectl, html, text=None): "Create a mime-message that will render as HTML or text, as appropriate" import MimeWriter import mimetools import 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) txtin = cStringIO.StringIO(text) writer = MimeWriter.MimeWriter(out) # Set up some basic headers. Place subject here # because smtplib.sendmail expects it to be in the # message body, 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 body writer.lastpart( ) msg = out.getvalue( ) out.close( ) return msg 10.9.3 DiscussionThis 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('[email protected]', '[email protected]', 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 they do, don't forget to embed two alternative versions of your message: the HTML version and a text-only version. Lots of folks still prefer character-mode mail readers (technically known as a mail user agent, or MUA), and it makes no sense to alienate them by sending mail that they can't conveniently read. This recipe shows how easy Python makes this. 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 this input, you can still prepare a text version on the fly; one way to do this 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 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. See Recipe 12.8 for some ideas on how to synthesize structured-text markup from plain text following these rather common conventions. The emails generated by this code have been successfully tested 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, others would be expected to work just as acceptably. 10.9.4 See AlsoRecipe 10.11 shows how Python 2.2's email package can be used to compose a MIME multipart message; Recipe 12.8 for other text synthesis options; documentation for the standard module email for a Python 2.2 alternative to classic Python modules such as mimetools and MimeWriter; Henry Minsky's article on MIME (http://www.arsdigita.com/asj/mime/) for information on the issues of how to send HTML mail. |
I l@ve RuBoard |