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
Versitile And Sturdy Python Email Class/script .
// Detailed script to send email through python. Can be called through sendEmail class or you can run it via command line. You can even pipe the body of the message from stdin!
#!/bin/env python2.3
#******************************************************************************* sendEmail.py
"""
Send email with given data or attachment files.
"""
#******************************************************************************* Imports
import sys,os
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.Utils import COMMASPACE, formatdate
from email.MIMEText import MIMEText
from email import Encoders
from optparse import OptionParser
from tempfile import NamedTemporaryFile
#=============================================================================== sendEmail
class sendEmail:
#=============================================================================== __init__
def __init__(self, msgTo='', msgFrom='', msgSubject='', msgBody='', attachmentDict={}, attachmentPaths=[]):
'''
Build and sends an email through local smtp server with the following options:
*msgTo = List of email addresses to send to or comma separated string of emails.
*msgFrom = String with email address to show as sent from.
*msgSubject = String with subject line
msgBody = String with data for message body.
attachmentDict = Dict of filename = content. Example: 'test.csv'='some,csv,file\nto,send,out'
attachmentPaths = List of paths to files that need to be sent.
* Required
Note that You must use the send function to send the email.
'''
self.msg = MIMEMultipart()
self.msgTo = msgTo
self.msgFrom = msgFrom
self.msgSubject = msgSubject
self.msgBody = msgBody
# Create and attach "files" from dict.
if attachmentDict:
for fileName in attachmentDict.keys():
tmpFile = NamedTemporaryFile()
tmpFile.write(attachmentDict[fileName])
tmpFile.flush()
self.msg.attach(self._encodeFile(fileName, tmpFile.name))
tmpFile.close()
# Attach passed files using paths if they exist.
if attachmentPaths:
for filePath in attachmentPaths:
if os.path.exists(filePath):
self.msg.attach(self._encodeFile(os.path.basename(filePath), filePath))
#=============================================================================== encodeFile
def _encodeFile(self, fileName, filePath):
'''
Internal method used to return an encoded file to be attached.
Allows for more readablility in code.
'''
part = MIMEBase('application', "octet-stream")
part.set_payload( open(filePath,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % fileName)
print 'Sucessfully Attached: ', os.path.basename(fileName)
return part
#=============================================================================== attachFile
def attachFile(self, filePath, fileName=''):
'''
Checks for valid filePath and then attaches the given fileName and filePath to the the message.
If no fileName is give then default name is assumed.
'''
if os.path.exists(filePath):
if not fileName:
fileName = os.path.basename(filePath)
self.msg.attach(self._encodeFile(fileName, filePath))
#=============================================================================== attachFile
def attachText(self, fileName,fileText):
'''
Options:
fileName = desired name of attachment.
fileText = list or string to attach as contents of file.
'''
if isinstance(fileText, list):
fileText = '\n'.join(fileText)
tmpFile = NamedTemporaryFile()
tmpFile.write(fileText)
tmpFile.flush()
self.msg.attach(self._encodeFile(fileName, tmpFile.name))
tmpFile.close()
#=============================================================================== send
def send(self, smtpAddress='localhost'):
'''
Sends the message using the passed smtpAddress or localhost if no address is specified.
'''
errText = '\n'
if not self.msgTo:
errText += 'No TO address\n'
elif not self.msgFrom:
errText += 'No FROM address\n'
elif not self.msgSubject:
errText += 'No SUBJECT line\n'
if errText.strip():
print errText + 'Message not sent.'
else:
self.msg.attach(MIMEText(self.msgBody))
if isinstance(self.msgTo, list):
self.msg['To'] = COMMASPACE.join(self.msgTo)
else:
self.msg['To'] = self.msgTo
self.msg['From'] = self.msgFrom.strip()
self.msg['Date'] = formatdate(localtime=True)
self.msg['Subject'] = self.msgSubject
smtp = smtplib.SMTP(smtpAddress)
smtp.sendmail(self.msgFrom, self.msgTo, self.msg.as_string())
smtp.close()
print 'Email Sent To: %s, From: %s, Subject: %s' %(self.msgTo, self.msgFrom, self.msgSubject)
#=============================================================================== getOptsAndArgs
def getOptsAndArgs(args):
#========================================================================== requiredInput
def requiredInput(prompt, name):
while True:
i = raw_input(prompt)
if i.strip():
return i
else:
print 'Please enter a(n) %s.' % name
#========================================================================== getMultiLineInput
def getMultiLineInput(prompt):
retLines = []
prompt = '-- %s (Empty to end) --\n' % prompt
newLine = raw_input(prompt)
while newLine:
retLines.append(newLine)
newLine = raw_input()
return '\n'.join(retLines)
#========================================================================== getAttachmentsInteractively
def getAttachmentsInteractively(options):
attachmentDict = {}
while True:
attachPrompt = raw_input('Attachment?\n([T]ext,[F]ile,[N]one)\t').upper()
if attachPrompt == 'T':
attachmentName = requiredInput('Attachment Name:\t', 'attachment name')
attachmentText = getMultiLineInput('Attachment Text')
attachmentDict[attachmentName] = attachmentText
elif attachPrompt == 'F':
attachmentPath = requiredInput('Attachment Path:\t', 'attachment path')
if os.path.exists(attachmentPath):
options.attachmentPaths.append(attachmentPath)
else:
print 'File does not exist: ', attachmentPath
else:
break
if attachmentDict:
options.attachmentDict = attachmentDict
#========================================================================== getOptsInteractively
def getOptsInteractively(options):
if not options.msgTo:
options.msgTo = requiredInput('To: \t', 'destination address')
if not options.msgFrom:
options.msgFrom = requiredInput('From: \t', 'from address')
if not options.msgSubject:
options.msgSubject = requiredInput('Subject: ', 'message subject')
if not options.msgBody:
options.msgBody = getMultiLineInput('Body')
getAttachmentsInteractively(options)
#========================================================================== checkRequired
def checkRequired(options):
errText = '\n'
if not options.msgTo:
errText += 'You must give an email address to send to using -t or --to=\n'
if not options.msgFrom:
errText += 'You must give an email address to send from using -f or --from=\n'
if not options.msgSubject:
errText += 'You must give a subject line using -s or --subject=\n'
return errText.strip()
#========================================================================== validateRequired
def validateRequired(validCheck):
if validCheck.strip():
parser.error(validCheck)
#========================================================================== parseOpts
parser = OptionParser()
parser.add_option('-i', '--interactive',
action='store_true', dest='runInteractive',
help='Input information in an interactive prompt.'
)
parser.add_option('-t', '--to',
action='store', dest='msgTo',
help='Email address to send to.'
)
parser.add_option('-f', '--from',
action='store', dest='msgFrom',
help='Email address to show as sent from.'
)
parser.add_option('-s', '--subject',
action='store', dest='msgSubject',
help='Output summary only. Exclude statistics section.'
)
parser.add_option('-b', '--body',
action='store', dest='msgBody',default='',
help='Text to send as body'
)
parser.add_option('-A', '--attachments-interactive',
action='store_true', dest='attachInteractive',
help='Input attachment information in an interactive prompt.'
)
parser.add_option('-p', '--attachment-paths',
action='store', dest='attachmentPaths',
help='Comma separated list of attachment files, works with one file as well'
)
parser.add_option('-S', '--smtp-address=',
action='store', dest='smtpAddress', default='localhost',
help='Comma separated list of attachment files, works with one file as well'
)
options, args = parser.parse_args()
options.attachmentDict = {}
if options.attachmentPaths:
options.attachmentPaths = options.attachmentPaths.split(',')
else:
options.attachmentPaths = []
checkText = checkRequired(options)
if not sys.stdin.isatty():
options.msgBody += sys.stdin.read()
validateRequired(checkText)
if options.runInteractive:
getOptsInteractively(options)
elif options.attachInteractive:
validateRequired(checkText)
getAttachmentsInteractively(options)
else:
validateRequired(checkText)
if options.attachmentPaths:
for filePath in options.attachmentPaths:
if not os.path.exists(filePath):
parser.error('File does not exist: ', filePath)
return options, args
#=============================================================================== __main__
if __name__ == '__main__':
options, args = getOptsAndArgs(sys.argv[1:])
message = sendEmail(msgTo=options.msgTo, msgFrom=options.msgFrom, msgSubject=options.msgSubject, msgBody=options.msgBody, attachmentDict=options.attachmentDict, attachmentPaths=options.attachmentPaths)
message.send(smtpAddress=options.smtpAddress)





