import email import imaplib import os import re import smtplib import sys import time import traceback from kraken.Whale import Whale class Kraken: """Polls an IMAP account, processing messages from the Inbox. """ def __init__(self, path): """Given a path to a Whale directory, instantiate the Whale. """ self.whale = Whale(path) def release(self): try: self.devour() except: print traceback.format_exc() sys.stdout.flush() time.sleep(90) self.release() def devour(self): """When it is time, poll and process. Make sure the account has these boxes: INBOX, Trash, Archive """ imap = self.whale.imap smtp = self.whale.smtp # open the IMAP connection and get everything in the INBOX try: M = imaplib.IMAP4_SSL(imap['server'], int(imap['port'])) except RuntimeError: print imap['server'] print traceback.format_exc() sys.stdout.flush() M.login(imap['username'], imap['password']) M.select() typ, raw = M.search(None, 'ALL') msg_nums = raw[0].split() if len(msg_nums) == 0: #print "no new mail" #sys.stdout.flush() return else: i_good = i_bad = 0 # track what we do for the log message for num in msg_nums: # get the From header and compare it to our membership lists From = self.from_addr(M,num).lower() if From not in self.whale.accept_from: # move it to the trash! M.copy(num, 'Trash') M.store(num, 'FLAGS.SILENT', '(\Deleted)') i_bad += 1 else: # get the raw email typ, raw = M.fetch(num, '(RFC822)') raw = raw[0][1] msg = email.message_from_string(raw) # tweak the headers if self.whale.mode == 'discussion': reply_to = imap['username'] else: reply_to = From try: msg.replace_header('Reply-To', reply_to) except KeyError: msg.__setitem__('Reply-To', reply_to) msg.add_header('X-Released-By','THE KRAKEN!!!!!!!!1') # and pass it on! server = smtplib.SMTP(smtp['server'],smtp['port']) server.starttls() server.ehlo() server.login(smtp['username'],smtp['password']) server.sendmail( imap['username'] , self.whale.send_to , msg.__str__() ) server.quit() # and move to archive M.copy(num, 'Archive') M.store(num, 'FLAGS.SILENT', '(\Deleted)') i_good += 1 M.close() M.logout() print 'new mail found: approved %s; rejected %s' % (i_good, i_bad) sys.stdout.flush() _from_addr = re.compile(r'[Ff]rom:.* ?') def from_addr(self, M=None, num=None, test_str=None): """ Given an IMAP connection and a message number, return an email address. >>> k = Kraken() >>> k 'chad.whitacre@zetaweb.com' >>> k.from_addr(test_str='From: chad@zetaweb.com') 'chad@zetaweb.com' """ if test_str is None: typ, raw = M.fetch(num, '(BODY[HEADER.FIELDS (FROM)])') FROM = raw[0][1] else: FROM = test_str return self._from_addr.search(FROM).group(1) try: return self._from_addr.search(FROM).group(1) except: print "error parsing: %s" % FROM sys.stdout.flush()