Package npsgd :: Module email_manager
[hide private]
[frames] | no frames]

Source Code for Module npsgd.email_manager

  1  # Author: Thomas Dimson [tdimson@gmail.com] 
  2  # Date:   January 2011 
  3  # For distribution details, see LICENSE 
  4  """NPSGD e-mail related module for blocking/non-blocking sends.""" 
  5  import smtplib 
  6  import Queue 
  7  from email.mime.audio import MIMEAudio 
  8  from email.mime.base import MIMEBase 
  9  from email.mime.image import MIMEImage 
 10  from email.mime.multipart import MIMEMultipart 
 11  from email.mime.text import MIMEText 
 12  from email.Utils import formatdate 
 13  from email import Encoders 
 14  from threading import Thread 
 15  import mimetypes 
 16  import logging 
 17  import socket 
 18  from config import config 
 19   
20 -class EmailSendError(RuntimeError): pass
21
22 -def blockingEmailSend(email):
23 """Attempt to send an e-mail synchronously, reporting an error if we fail.""" 24 try: 25 s = smtpServer() 26 except socket.gaierror, e: 27 raise EmailSendError("Unable to connect to smtp server") 28 29 30 try: 31 logging.info("Connected to SMTP server, sending email") 32 email.sendThrough(s) 33 finally: 34 s.close()
35 36 email_manager_thread = None
37 -def backgroundEmailSend(email):
38 """Attempt to send an e-mail asynchronously, spawning a background thread if necesarry. 39 40 This method sends an e-mail in the background using an e-mail thread. Note that 41 this has a side effect of actually spawning an e-mail thread if none exists already. 42 """ 43 44 global email_manager_thread 45 if email_manager_thread == None: 46 email_manager_thread = EmailManagerThread() 47 email_manager_thread.start() 48 49 email_manager_thread.addEmail(email)
50
51 -def smtpServer():
52 smtpserver = smtplib.SMTP(config.smtpServer, config.smtpPort) 53 smtpserver.ehlo() 54 if config.smtpUseTLS: 55 smtpserver.starttls() 56 if config.smtpUseAuth: 57 smtpserver.ehlo() 58 smtpserver.login(config.smtpUsername, config.smtpPassword) 59 60 return smtpserver
61
62 -class EmailManagerThread(Thread):
63 """Thread for sending e-mail in the background (using a queue of e-mails).""" 64
65 - def __init__(self):
66 Thread.__init__(self) 67 self.daemon = True 68 self.queue = Queue.Queue()
69
70 - def addEmail(self, email):
71 self.queue.put(email)
72
73 - def run(self):
74 """Blocks on the queue until it has an e-mail in it, then send it.""" 75 while True: 76 try: 77 email = self.queue.get(True) 78 logging.info("Email Manager: Found email in the queue, attempting to send") 79 blockingEmailSend(email) 80 except Exception: 81 logging.exception("Unhandled exception in email thread!") 82 self.queue.put(email)
83
84 -class Email(object):
85 """Actual e-mail object containing all information needed to send an e-mail. 86 87 The e-mail object includes the recipient, subject, body, attachments and 88 also contains a method to send through a given smtp server.""" 89
90 - def __init__(self, recipient, subject, body, binaryAttachments=[], textAttachments=[]):
91 self.recipient = recipient 92 self.subject = subject 93 self.body = body 94 self.binaryAttachments = binaryAttachments 95 self.textAttachments = textAttachments
96
97 - def sendThrough(self, smtpServer):
98 """Sends this e-mail through a given smtp server (blocking).""" 99 msg = MIMEMultipart() 100 #headers 101 msg['To'] = self.recipient 102 if len(config.cc) > 0: 103 msg['Cc'] = ",".join(config.cc) 104 msg['From'] = config.fromAddress 105 msg['Subject'] = self.subject 106 107 #actual recipients 108 recipients = [self.recipient] + config.cc + config.bcc 109 110 msg.attach(MIMEText(self.body)) 111 112 for (name, attach) in self.textAttachments: 113 part = MIMEText(attach, 'plain', 'UTF-8') 114 part.add_header("Content-Disposition", "attachment; filename=%s" % name) 115 msg.attach(part) 116 117 for (name, attach) in self.binaryAttachments: 118 ctype, encoding = mimetypes.guess_type(name) 119 if ctype is None or encoding is not None: 120 ctype = 'application/octet-stream' 121 122 maintype, subtype = ctype.split('/', 1) 123 if maintype == 'text': 124 part = MIMEText(attach, _subtype=subtype) 125 elif maintype == 'image': 126 part = MIMEImage(attach, _subtype=subtype) 127 elif maintype == 'audio': 128 part = MIMEAudio(attach, _subtype=subtype) 129 else: 130 part = MIMEBase(maintype, subtype) 131 part.set_payload(attach) 132 Encoders.encode_base64(part) 133 134 part.add_header("Content-Disposition", "attachment; filename=%s" % name) 135 msg.attach(part) 136 137 logging.info("Email: constructed email object, sending to %s", ", ".join(recipients)) 138 smtpServer.sendmail(config.fromAddress, recipients, msg.as_string()) 139 logging.info("Email: sent")
140