Since I posted about using Python to send HTML email, things have changed in Python’s standard library. While that method still works, it’s better to use the new email package.



For the purposes of this post, I am assuming the following:

Python 2.x (I have Python 2.6 installed on my development server)

Linux

Lynx is installed

import os def html2text( html ): fname = os.tmpnam() fp = open(fname, 'w') fp.write(html) fp.close() fp = os.popen('cat %s | lynx -dump -force_html -stdin' % fname) buff = fp.read() fp.close() return buff

The html2text function takes a given HTML document (either local or a you can use an external URL) and converts it to a plain text document. It uses os.popen to do this, by piping the document through Lynx and using that program as a filter to do the conversion.

import email from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText def createhtmlmail (html, text, subject): msg = MIMEMultipart('alternative') part1 = MIMEText(text, 'plain') part2 = MIMEText(html, 'html') msg.attach(part1) msg.attach(part2) return msg

createhtmlmail does the heavy lifting of making the MIME attachments and adding them to the email message. You may notice that I kept the function signature the same as that used in my earlier post onsending HTML email from Python; this way, I was able to use these new functions as a drop-in replacement to what I had in my production environment.

import email import os from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText def compose_mail(html, subject, to_mail, from_mail): text = html2text(html) email_data = createhtmlmail(html, text, subject) email_data['Subject'] = subject email_data['From'] = reply_mail email_data['To'] = to_mail email_data["Date"] = email.Utils.formatdate(localtime=True) return email_data

Here will build the actual email message, and set the Subject, From, and To headers. While Subject is technically optional, some MTA’s and MUA’s complain about mails with Subject headers; I’ve found it easier to always set it.

import smtplib def send_mail(from_mail, to_mail, email_data): server = smtplib.SMTP("localhost") server.sendmail(from_mail, to_mail, email_data) server.quit()

I have a local sendmail running on my Linux machines, so I can use localhost as my SMTP server; you may need to change it according to your actual environment.

With those functions in place, we can now send a MIME multipart email, with the following:

email_data = compose_mail(body, subject, to_mail, from_mail) send_mail(from_mail, to_mail, email_data.as_string())

The only part of this example code that relies on a non-typical piece of software is the html2text function. I use Lynx as the filtering process, but you can replace that with something more appropriate for your platform and environment.

You can download the full file here.