Credit: Art Gillespie
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.
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 creatlmail(subject,l, 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
importllib, formatter
textout = cStringIO.StringIO( )
formtext = formatter.AbstractFormatter(formatter.DumbWriter(textout))
parser =llib.HTMLParser(formtext)
parser.feedl)
parser.close( )
text = textout.getvalue( )
del textout, formtext, parser
out = cStringIO.StringIO( )# output buffer for our message
htmlin = cStringIO.StringIOl)# 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("textl", [("charset", 'us-ascii')])
mimetools.encodelin, 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 msgThis 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("newsletterl", 'r')
html = f.read( )
f.close( )
try:
f = open("newsletter.txt", 'r')
text = f.read( )
except IOError:
text = None
subject = "Today's Newsletter!"
message = creatlmail(subject,l, 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
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. 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,
text = os.popen('lynx -dump %s' % tempfile).read( ) See Also