#------------------------------------------------------------------------------ # Name: attdownload.py # Author: Suresh Kumar MP # Last Modified: 09/29/06 # Description: This python script monitors the IMAP mail server for the given # account and moves the mails with attachments to "Downloadedmails" # folder in server after downloading the attachments to the individual # directories on localmachine with a timestamp. #------------------------------------------------------------------------------ import getopt, getpass, os, sys, time import imaplib import email, email.Errors, email.Header, email.Message, email.Utils from time import strftime from time import sleep Usage = """Usage: %s --user --password --frequency --user Provide for authentication on --password Password for the given user --frequency Provide the mail server polling frequency in seconds Example: attdownload.py --user username --password password --frequency 300 10.133.23.124 """ AttachDir = '.' # Attachment Directory Path DeleteMessages = 0 SaveAttachments = 1 # Save all attachments found User = None # IMAP4 user Password = None # User password Frequency = None # Mail server polling frequency exists = 0 name = 0 def usage(reason=''): sys.stdout.flush() if reason: sys.stderr.write('\t%s\n\n' % reason) head, tail = os.path.split(sys.argv[0]) sys.stderr.write(Usage % tail) sys.exit(1) def args(): try: optlist, args = getopt.getopt(sys.argv[1:], '?',['user=', 'password=', 'frequency=']) except getopt.error, val: usage(val) global SaveAttachments global User global Password global Frequency for opt,val in optlist: if opt == '--user': User = val elif opt == '--password': Password = val elif opt == '--frequency': Frequency = float(val) else: usage() if len(args) != 1: usage() return args[0] def write_file(filename, addr, data): os.chdir(addr) fd = open(filename, "wb") fd.write(data) fd.close() def gen_filename(name, mtyp, addr, date, n): timepart = strftime("%d %b %y %H_%M_%S") file = email.Header.decode_header(name)[0][0] file = os.path.basename(file) print "Saved attachment " + file + " from " + addr print "\n" path = os.path.join(AttachDir, file) pre, ext = os.path.splitext(file) pre = pre + "_" + timepart path = '%s%s' % (os.path.join(AttachDir, pre), ext) return path def error(reason): sys.stderr.write('%s\n' % reason) sys.exit(1) def walk_parts(msg, addr, date, count, msgnum): for part in msg.walk(): if part.is_multipart(): continue dtypes = part.get_params(None, 'Content-Disposition') if not dtypes: if part.get_content_type() == 'text/plain': continue ctypes = part.get_params() if not ctypes: continue for key,val in ctypes: if key.lower() == 'name': filename = gen_filename(val, part.get_content_type(), addr, date, count) break else: continue else: attachment,filename = None,None for key,val in dtypes: key = key.lower() if key == 'filename': filename = val if key == 'attachment': attachment = 1 if not attachment: continue filename = gen_filename(filename, part.get_content_type(), addr, date, count) try: data = part.get_payload(decode=1) except: typ, val = sys.exc_info()[:2] warn("Message %s attachment decode error: %s for %s ``%s''" % (msgnum, str(val), part.get_content_type(), filename)) continue if not data: warn("Could not decode attachment %s for %s" % (part.get_content_type(), filename)) continue if type(data) is type(msg): count = walk_parts(data, addr, date, count, msgnum) continue if SaveAttachments: exists = "0" try: curdir= os.getcwd() list = os.listdir('.\\') for name in list: if name == addr: exists = "1" break if exists == "1": write_file(filename, addr, data) os.chdir(curdir) else: os.mkdir(addr) write_file(filename, addr, data) os.chdir(curdir) exists == "0" os.chdir(curdir) except IOError, val: error('Could not create "%s": %s' % (filename, str(val))) count += 1 return count def process_message(text, msgnum): try: msg = email.message_from_string(text) except email.Errors.MessageError, val: warn("Message %s parse error: %s" % (msgnum, str(val))) return text date = msg['Date'] or 'Thu, 18 Sep 2006 12:02:27 +1000' date = time.strftime('%Y_%m_%d.%T', email.Utils.parsedate(date)) addr = email.Utils.parseaddr(msg['From'])[1] attachments_found = walk_parts(msg, addr, date, 0, msgnum) if attachments_found: return '' else: return None def read_messages(fd): data = []; app = data.append for line in fd: if line[:5] == 'From ' and data: yield ''.join(data) data[:] = [] app(line) if data: yield ''.join(data) def process_server(host): global DeleteAttachments try: mbox = imaplib.IMAP4(host) except: typ,val = sys.exc_info()[:2] error('Could not connect to IMAP server "%s": %s' % (host, str(val))) if User or mbox.state != 'AUTH': user = User or getpass.getuser() if Password == "": pasw = getpass.getpass("Please enter password for %s on %s: " % (user, host)) else: pasw = Password try: typ,dat = mbox.login(user, pasw) except: typ,dat = sys.exc_info()[:2] if typ != 'OK': error('Could not open INBOX for "%s" on "%s": %s' % (user, host, str(dat))) mbox.select('Inbox') #mbox.select(readonly=(DeleteMessages)) typ, dat = mbox.search(None, 'ALL') mbox.create("DownloadedMails") deleteme = [] for num in dat[0].split(): typ, dat = mbox.fetch(num, '(RFC822)') if typ != 'OK': error(dat[-1]) message = dat[0][1] if process_message(message, num) == '': deleteme.append(num) if deleteme == []: print "\n" print "No mails with attachment found in INBOX" deleteme.sort() for number in deleteme: mbox.copy(number, 'DownloadedMails') mbox.store(number, "+FLAGS.SILENT", '(\\Deleted)') mbox.expunge() mbox.close() mbox.logout() def main(): file_or_server = args() print "\n" print "Monitoring the Mail server " + file_or_server + " for account " + User while 1: process_server(file_or_server) printfre = str(Frequency) print "Sleeping for " + printfre + " seconds..." sleep(Frequency) if __name__ == '__main__': try: main() except KeyboardInterrupt: pass