From 51fd560f92a02caf9ddbbbd6ca25822e9a116c22 Mon Sep 17 00:00:00 2001 From: "Fredrick W. Warren" Date: Tue, 21 Aug 2018 12:46:29 -0700 Subject: [PATCH] Added module for emailing --- emailer.py | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100755 emailer.py diff --git a/emailer.py b/emailer.py new file mode 100755 index 0000000..bbaf22d --- /dev/null +++ b/emailer.py @@ -0,0 +1,223 @@ +#!/usr/bin/python2 + +from email import encoders +from email.mime.audio import MIMEAudio +from email.mime.base import MIMEBase +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +import mimetypes +import os +import re +import smtplib + +class Email: + """ + This class handles the creation and sending of email messages + via SMTP. This class also handles attachments and can send + HTML messages. The code comes from various places around + the net and from my own brain. + """ + def __init__(self, smtpServer): + """ + Create a new empty email message object. + + @param smtpServer: The address of the SMTP server + @type smtpServer: String + """ + self._textBody = None + self._htmlBody = None + self._bcc = [] + self._cc = [] + self._subject = "" + self._smtpServer = smtpServer + self._reEmail = re.compile("^([\\w \\._]+\\<[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\>|[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)$") + self.clearRecipients() + self.clearAttachments() + + def send(self): + """ + Send the email message represented by this object. + """ + # Validate message + if self._textBody is None and self._htmlBody is None: + raise Exception("Error! Must specify at least one body type (HTML or Text)") + if len(self._to) == 0: + raise Exception("Must specify at least one recipient") + + # Create the message part + if self._textBody is not None and self._htmlBody is None: + msg = MIMEText(self._textBody, "plain") + elif self._textBody is None and self._htmlBody is not None: + msg = MIMEText(self._htmlBody, "html") + else: + msg = MIMEMultipart("alternative") + msg.attach(MIMEText(self._textBody, "plain")) + msg.attach(MIMEText(self._htmlBody, "html")) + # Add attachments, if any + if len(self._attach) != 0: + tmpmsg = msg + msg = MIMEMultipart() + msg.attach(tmpmsg) + for fname,attachname in self._attach: + if not os.path.exists(fname): + print "File '%s' does not exist. Not attaching to email." % fname + continue + if not os.path.isfile(fname): + print "Attachment '%s' is not a file. Not attaching to email." % fname + continue + # Guess at encoding type + ctype, encoding = mimetypes.guess_type(fname) + if ctype is None or encoding is not None: + # No guess could be made so use a binary type. + ctype = 'application/octet-stream' + maintype, subtype = ctype.split('/', 1) + if maintype == 'text': + fp = open(fname) + attach = MIMEText(fp.read(), _subtype=subtype) + fp.close() + elif maintype == 'image': + fp = open(fname, 'rb') + attach = MIMEImage(fp.read(), _subtype=subtype) + fp.close() + elif maintype == 'audio': + fp = open(fname, 'rb') + attach = MIMEAudio(fp.read(), _subtype=subtype) + fp.close() + else: + fp = open(fname, 'rb') + attach = MIMEBase(maintype, subtype) + attach.set_payload(fp.read()) + fp.close() + # Encode the payload using Base64 + encoders.encode_base64(attach) + # Set the filename parameter + if attachname is None: + filename = os.path.basename(fname) + else: + filename = attachname + attach.add_header('Content-Disposition', 'attachment', filename=filename) + msg.attach(attach) + # Some header stuff + msg['Subject'] = self._subject + msg['From'] = self._from + msg['To'] = ", ".join(self._to) + msg['Cc'] = ", ".join(self._cc) + msg.preamble = "You need a MIME enabled mail reader to see this message" + # Send message + msg = msg.as_string() + server = smtplib.SMTP(self._smtpServer) + server.sendmail(self._from, self._to + self._cc + self._bcc, msg) + server.quit() + + def setSubject(self, subject): + """ + Set the subject of the email message. + """ + self._subject = subject + + def setFrom(self, address): + """ + Set the email sender. + """ + if not self.validateEmailAddress(address): + raise Exception("Invalid email address '%s'" % address) + self._from = address + + def clearRecipients(self): + """ + Remove all currently defined recipients for + the email message. + """ + self._to = [] + self._cc = [] + self._bcc = [] + + def addRecipient(self, address): + """ + Add a new recipient to the email message. + """ + if not self.validateEmailAddress(address): + raise Exception("Invalid email address '%s'" % address) + self._to.append(address) + + def addCC(self, address): + """ + Add a new carbon copy recipient to the email message. + """ + if not self.validateEmailAddress(address): + raise Exception("Invalid cc email address '%s'" % address) + self._cc.append(address) + + def addBCC(self, address): + """ + Add a new blind carbon copy recipient to the email message. + """ + if not self.validateEmailAddress(address): + raise Exception("Invalid bcc email address '%s'" % address) + self._bcc.append(address) + + def setTextBody(self, body): + """ + Set the plain text body of the email message. + """ + self._textBody = body + + def setHtmlBody(self, body): + """ + Set the HTML portion of the email message. + """ + self._htmlBody = body + + def clearAttachments(self): + """ + Remove all file attachments. + """ + self._attach = [] + + def addAttachment(self, fname, attachname=None): + """ + Add a file attachment to this email message. + + @param fname: The full path and file name of the file + to attach. + @type fname: String + @param attachname: This will be the name of the file in + the email message if set. If not set + then the filename will be taken from + the fname parameter above. + @type attachname: String + """ + if fname is None: + return + self._attach.append( (fname, attachname) ) + + def validateEmailAddress(self, address): + """ + Validate the specified email address. + + @return: True if valid, False otherwise + @rtype: Boolean + """ + if self._reEmail.search(address) is None: + return False + return True + +if __name__ == "__main__": + print "Tests go here..." +""" + # Run some tests + mFrom = 'fredw@northriverboats.com' + mTo = "fred.warren@gmail.com" + m = Email('northriverboats-com.mail.protection.outlook.com') + m.setFrom(mFrom) + m.addRecipient(mTo) + m.addCC("fredw@northriverboats.com") + m.addBCC("w.brokenbourgh@pismotek.com") + + m.setSubject("Text and HTML Message with CC and BCC") + m.setTextBody("You should not see this text in a MIME aware reader") + m.setHtmlBody("The following should be bold. If this works Will, you will be BCC'd on this.") + m.addAttachment('/tmp/shot.png') + m.send() +"""