sending HTML emails

267 views
Skip to first unread message

kralin

unread,
Jul 10, 2009, 2:31:08 PM7/10/09
to web2py Web Framework
I spent the whole afternoon trying to send an HTML formatted email
with web2py.
while I cannote use smtplib directly, cause it seems not to work, and
I think this should be "normal" in the framework.
however in the current release (Version 1.65.0 (2009-07-01 12:16:25))
it is not possible to alter the content-type, or any other header for
the email using the gluon.tools.Mail class.
this happens because anu message that is passed to the mail=Mail()
object is attached to this string before beeing sent:


msg = '''From: %s\r
To: %s\r
Subject: %s\r
\r
%s'''\


and the double newlines close the headers.

so it would be very useful to also set at least something link this:

def send(
self,
to,
subject='None',
message='None',
headers='\r\n'
):


msg = '''From: %s\r
To: %s\r
Subject: %s\r
\r
%s'''\
% (self.settings.sender, ', '.join(to),
subject,headers,
message)


so that it will be possible to pass directly some header strings or
pass an empty string as headers, and put them in the message.
this way they can be correctly recognized.

hope this helps
cheers


mdipierro

unread,
Jul 10, 2009, 4:15:25 PM7/10/09
to web2py Web Framework
While this can be and something like this can be added it is my
understanding that you do not need to change the header to send html
emails. You need to use the MIME encoding and that should be
transparent to what mail.send does now. If I am wrong please provide
an example of how to change the headers to send a MIME encoded
message.

Yarko Tymciurak

unread,
Jul 10, 2009, 4:15:33 PM7/10/09
to web...@googlegroups.com

mdipierro

unread,
Jul 10, 2009, 4:24:04 PM7/10/09
to web2py Web Framework
Yarko, I can tell you are still at web2py 1.52. ;-)

Massimo

On Jul 10, 3:15 pm, Yarko Tymciurak <yark...@gmail.com> wrote:
> See
>
> http://bazaar.launchpad.net/~yarkot1/web2conf/pycon2009site/annotate/...
>
> (just use send()  instead of t2.eamil() )
>

Yarko Tymciurak

unread,
Jul 10, 2009, 4:42:13 PM7/10/09
to web...@googlegroups.com
well, web2conf was... I found your update (actually I think its on launchpad) and it looks like you worked off of something older than what we ran at the conference, so will need to merge and update all the parts from last years conference site.

I'll try to do that before you leave so you can have a merged copy on your trip, for what we discussed yesterday.

kralin

unread,
Jul 10, 2009, 5:31:16 PM7/10/09
to web2py Web Framework
I've also tried to use MIME to encode both the html, and an
alternative text/html message, however all the encoding goes after
the double newline
and is not interpreted as an header.

so Yarko are you saying that by doing send(message='hello message')
instead of send(to=['m...@me.com'], message='hello message')
it should worrk by including the correct headers in the message?

mdipierro

unread,
Jul 10, 2009, 5:39:44 PM7/10/09
to web2py Web Framework
Here is the problem. The current implementation of Mail is designed to
be cross platform, i.e. work on GAE. It has the same API as GAE.
Unless we figure out how to send MIME email messages on GAE, if you
want to send MIME you should not use Mail native SMTP.

On Jul 10, 4:31 pm, kralin <andrea.pierle...@gmail.com> wrote:
> I've also tried to use MIME to encode both the html, and an
> alternative text/html message, however all the encoding goes after
> the double newline
> and is not interpreted as an header.
>
> so Yarko are you saying that by doing send(message='hello message')
> instead of send(to=['...@me.com'], message='hello message')

kralin

unread,
Jul 10, 2009, 5:46:07 PM7/10/09
to web2py Web Framework
ok, so smtplib should work instead of Mail?

mdipierro

unread,
Jul 10, 2009, 6:44:18 PM7/10/09
to web2py Web Framework
yes.

mdipierro

unread,
Jul 10, 2009, 6:46:24 PM7/10/09
to web2py Web Framework
import smtplib
server = smtplib.SMTP(host, port)
server.ehlo()
server.starttls()
server.ehlo()
server.login(username, password)
server.sendmail(sender, to, msg)
server.quit()

look into the docs for datils. Mind that the docs say .ehlo and .helo
are the same. They are not. The latter does not work with starttls


On Jul 10, 4:46 pm, kralin <andrea.pierle...@gmail.com> wrote:

kralin

unread,
Jul 11, 2009, 4:22:32 AM7/11/09
to web2py Web Framework
yes, I've already tryed this way, after looking at tools.py
maybe I'm doing something wrong, I'm going to recheck...

thanks

Brian M

unread,
Jul 16, 2009, 10:53:51 PM7/16/09
to web2py Web Framework
I've found a solution for sending multi-part emails (text & html) and
even embedded images.

In your controller (or a custom module)

from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage

#helper function to build a multi-part mime email
def _multipart_email(sender, recipient, subject, message_text,
message_html, attach_image):
#Taken from http://code.activestate.com/recipes/473810/ with very
minor changes

# Define these once; use them twice!
strFrom = sender
strTo = recipient

# Create the root message and fill in the from, to, and subject
headers
msgRoot = MIMEMultipart('related')
msgRoot['Subject'] = subject
msgRoot['From'] = strFrom
msgRoot['To'] = strTo
msgRoot.preamble = 'This is a multi-part message in MIME format.'

# Encapsulate the plain and HTML versions of the message body in
an
# 'alternative' part, so message agents can decide which they want
to display.
msgAlternative = MIMEMultipart('alternative')
msgRoot.attach(msgAlternative)

msgText = MIMEText(message_text)
msgAlternative.attach(msgText)

# We reference the image in the IMG SRC attribute by the ID we
give it below
msgText = MIMEText(message_html, 'html')
msgAlternative.attach(msgText)

if attach_image:
# This example assumes the image is in the current directory
or you've passed the full path
fp = open(attach_image, 'rb')
msgImage = MIMEImage(fp.read())
fp.close()

#you can refer to this image as <img src="cid:image1"> in your
html message.
# Define the image's ID as referenced above
msgImage.add_header('Content-ID', '<image1>')
msgRoot.attach(msgImage)
return msgRoot


In your controller:

#visit this page and you'll get an email
def email():
host = 'smtp.gmail.com' #your mail server
port = 587 #port if non-standard
username = 'your_username'
password = 'your_password'

import smtplib
server = smtplib.SMTP(host, port)
server.ehlo()
server.starttls()
server.ehlo()
server.login(username, password)

context=dict(name='John Doe', ship_date='July 15,
2009',amount_owed=25.50,num_items=2)

#use web2py views to get an html and plain text version of the
message
message_html=response.render('default/
email_template.html',context) #template for the html version
message_text = response.render('default/
email_template.txt',context) #template for the text only version

sender = 'yo...@NOTSPAMMING.com'
recipient = 'cust...@host.com'

subject = "We've shipped your order"

#build the multi-part MIME message
message = _multipart_email(sender, recipient, subject,
message_text, message_html, 'image.jpg')

#and send it
server.sendmail(sender, recipient, message.as_string())
server.quit()

print message
return dict(status='email
sent',to=recipient,subject=subject,message=message.as_string())


Perhaps someone else here can use this and maybe even integrate it
into web2py in a more standard way.

~Brian

On Jul 11, 3:22 am, kralin <andrea.pierle...@gmail.com> wrote:
> yes, I've already tryed this way, after looking at tools.py
> maybe I'm doing something wrong, I'm going to recheck...
>
> thanks
>
> On 11 Lug, 00:46, mdipierro <mdipie...@cs.depaul.edu> wrote:
>
> > import smtplib
> > server = smtplib.SMTP(host, port)
> > server.ehlo()
> > server.starttls()
> > server.ehlo()
> > server.login(username, password)
> > server.sendmail(sender, to, msg)
> > server.quit()
>
> > look into the docs for datils. Mind that the docs say .ehlo and .helo
> > are the same. They are not. The latter does not work with starttls
>
> > On Jul 10, 4:46 pm, kralin <andrea.pierle...@gmail.com> wrote:
>
> > > ok, so smtplib should work instead of Mail?
>
> > > On 10 Lug, 23:39, mdipierro <mdipie...@cs.depaul.edu> wrote:
>
> > > > Here is the problem. The current implementation of Mail is designed to
> > > > be cross platform, i.e. work on GAE. It has the same API as GAE.
> > > > Unless we figure out how to send MIMEemailmessages on GAE, if you
> > > > want to send MIME you should not use Mail native SMTP.
>
> > > > On Jul 10, 4:31 pm, kralin <andrea.pierle...@gmail.com> wrote:
>
> > > > > I've also tried to use MIME to encode both thehtml, and an
> > > > > alternative text/htmlmessage, however all the encoding goes after
> > > > > the double newline
> > > > > and is not interpreted as an header.
>
> > > > > so  Yarko are you saying that by doing  send(message='hello message')
> > > > > instead of send(to=['...@me.com'], message='hello message')
> > > > > it should worrk by including the correct headers in the message?
>
> > > > > On 10 Lug, 22:15, mdipierro <mdipie...@cs.depaul.edu> wrote:
>
> > > > > > While this can be and something like this can be added it is my
> > > > > > understanding that you do not need to change the header to sendhtml
> > > > > > emails. You need to use the MIME encoding and that should be
> > > > > > transparent to what mail.send does now. If I am wrong please provide
> > > > > > an example of how to change the headers to send a MIME encoded
> > > > > > message.
>
> > > > > > On Jul 10, 1:31 pm, kralin <andrea.pierle...@gmail.com> wrote:
>
> > > > > > > I spent the whole afternoon trying to send anHTMLformattedemail
> > > > > > > with web2py.
> > > > > > > while I cannote use smtplib directly, cause it seems not to work, and
> > > > > > > I think this should be "normal" in the framework.
> > > > > > > however in the current release (Version 1.65.0 (2009-07-01 12:16:25))
> > > > > > > it is not possible to alter the content-type, or any other header for
> > > > > > > theemailusing the gluon.tools.Mail class.

mdipierro

unread,
Jul 16, 2009, 10:59:47 PM7/16/09
to web2py Web Framework
This is useful.
In principle you could just use:

mail=Mail()
mail.send(to..., subject,..., message=message.as_string())

or am I missing something?
Would you post an entry in AlterEgo?

Massimo

On Jul 16, 9:53 pm, Brian M <bmere...@gmail.com> wrote:
> I've found a solution for sending multi-part emails (text & html) and
> even embedded images.
>
> In your controller (or a custom module)
>
> from email.MIMEMultipart import MIMEMultipart
> from email.MIMEText import MIMEText
> from email.MIMEImage import MIMEImage
>
> #helper function to build a multi-part mime email
> def _multipart_email(sender, recipient, subject, message_text,
> message_html, attach_image):
>     #Taken fromhttp://code.activestate.com/recipes/473810/with very
>     sender = 'y...@NOTSPAMMING.com'
>     recipient = 'custo...@host.com'

Brian M

unread,
Jul 16, 2009, 11:27:16 PM7/16/09
to web2py Web Framework
Yes, using web2py's Mail() as you described probably works too. To be
honest I just didn't bother trying but I suppose your Mail helper is
likely just using smtplib in the background. The sending part is
easy, it's building the multi-part MIME message that I suspect has
been tricky for people.

I'll try to get this added to AlterEgo over the weekend.

mdipierro

unread,
Jul 16, 2009, 11:31:36 PM7/16/09
to web2py Web Framework
Thanks Brian. I may include your example in the new book since this is
very useful.

Massimo

Brian M

unread,
Jul 17, 2009, 8:34:44 AM7/17/09
to web2py Web Framework
Massimo,

Feel free to stick it in the new version of the book. I'll see if I
can't test it over the weekend with your Mail() function. I might even
try to make it so you can attach multiple images/files by passing a
list of files & what you want to refer to them by in the html? So
maybe something like:

attachment1 = dict(f='image1.jpg',cid='image1')
attachment2 = dict(f='logo.png',cid='image2')
attach_files = [attachment1, attachment2]
message = _multipart_email(sender, recipient, subject, message_text,
message_html, attach_files)

~Brian
Reply all
Reply to author
Forward
0 new messages