DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world
Python Send Email With Html And Plain Versions And Attachments
import os.path
import types
import smtplib
import email.Message
from email import Encoders
from email.MIMEAudio import MIMEAudio
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.MIMEImage import MIMEImage
from email.MIMEText import MIMEText
import mimetypes
class SendMail(object):
'''The swiss army knife of email programs. Here are some of the features:
1) you can build parts of the message in pieces. This is useful for when
you need to send out lots of emails with similar content. For example,
I needed to added a unique unsubcribe token to each email. The email had
a large attachment. This made it so I did not have to reprocess the
attachment for each email.
2) allows you to include both html and plain text versions of the message
in the email.
3) handles the encoding of a wide range of attachment file types.
4) sends the email with the TLS protocol if the server uses TLS
gmail uses TLS.
This code was pieced together from snippets of code found using google.
How to use? Just look down the list of methods. Use the ones you need.
It should be pretty obvious. You will need to set the attributes:
"from_email_addr" and "subject" directly before calling send.
This code has NOT been throughly tested because there are too many combinations.
I just test the combinations I need.
'''
def __init__(self,smtpserver,smtpuser = '',smtppass = '',port=None, debug=False):
self.smtpserver=smtpserver
self.smtpuser=smtpuser
self.smtppass=smtppass
self.port=port
self.debug=debug
self.encoded_attachments=[]
self.cc_list=[]
def add_attachments(self,attachment_list):
'''attachment_list: a list of full file paths'''
self.encoded_attachments=[]
for path in attachment_list:
dirname,filename=os.path.split(path)
# Guess the content type based on the file's extension. Encoding
# will be ignored, although we should check for simple things like
# gzip'd or compressed files.
ctype, encoding = mimetypes.guess_type(path)
if ctype is None or encoding is not None:
# No guess could be made, or the file is encoded (compressed), so
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
if maintype == 'text':
fp = open(path)
# Note: we should handle calculating the charset
msg = MIMEText(fp.read(), _subtype=subtype)
fp.close()
elif maintype == 'image':
fp = open(path, 'rb')
msg = MIMEImage(fp.read(), _subtype=subtype)
fp.close()
elif maintype == 'audio':
fp = open(path, 'rb')
msg = MIMEAudio(fp.read(), _subtype=subtype)
fp.close()
else: # includes MS Word docs
fp = open(path, 'rb')
msg = MIMEBase(maintype, subtype)
msg.set_payload(fp.read())
fp.close()
# Encode the payload using Base64
Encoders.encode_base64(msg)
# Set the filename parameter
msg.add_header('Content-Disposition', 'attachment', filename=filename)
self.encoded_attachments.append(msg)
def add_to(self,to_list):
self.to_list=to_list
self.to_str=','.join(to_list)
def add_cc(self,cc_list):
self.cc_list=cc_list
self.cc_str=','.join(cc_list)
def add_body(self,body):
if type(body) is types.StringType:
self.body=MIMEText(body,'plain')
else:
self.body=MIMEMultipart('alternative')
for k in body:
self.body.attach(MIMEText(body[k],k))
def send(self):
'''No error checking. It should just crash if some stuff is not setup. '''
message=MIMEMultipart()
message.preamble = 'You will not see this in a MIME-aware mail reader.\n'
message.epilogue = '' # To guarantee the message ends with a newline
message.attach(self.body)
message['To']=self.to_str
if self.cc_list:
message['CC']=self.cc_str
# Set these attributes up directly before calling this method
message['Subject'] = self.subject
message['From']=self.from_email_addr
print self.encoded_attachments
for a in self.encoded_attachments:
message.attach(a)
# Send it
server = smtplib.SMTP(self.smtpserver,self.port)
try:
server.set_debuglevel(self.debug)
server.ehlo()
# If we can encrypt this session, do it
if server.has_extn('STARTTLS'):
server.starttls()
server.ehlo() # re-identify ourselves over TLS connection
server.login(self.smtpuser, self.smtppass)
smtpresult =server.sendmail(self.from_email_addr, self.to_list+self.cc_list, message.as_string())
finally:
server.quit()
if smtpresult:
for recip in smtpresult.keys():
print """Could not delivery mail to: %s Server said: %s %s""" \
% (recip, smtpresult[recip][0], smtpresult[recip][1])
return False
else:
return True
def send_simple_email(self,to_list,from_email_addr,subject,body,attachment_list=[],
cc_list=[]):
'''A wrapper for if you do not need to do things in pieces. You can also use this
as a guide for how to build up an email in pieces.
'''
self.add_to(to_list)
self.add_cc(cc_list)
self.from_email_addr=from_email_addr
self.subject=subject
self.add_body(body)
self.add_attachments(attachment_list)
return self.send()
if __name__=="__main__":
smtpuser = 'my_email@gmail.com'
smtppass=raw_input('Enter gmail password->')
body={}
body['html']='<h1>hi</h1>'
body['plain']='hello'
sm=SendMail('smtp.gmail.com', smtpuser = smtpuser, smtppass = smtppass, port=587)
r=sm.send_simple_email(['to_someone@yahoo.com'],'my_email@gmail.com','Test - from Fred',
body,attachment_list=[r'C:\Documents and Settings\my_media\uploads\Case-of-the-Week invite 02-24-10.doc'])
print r





