"""Read mail from a POP3 account and write a Unix Mailbox file""" import string, re import socket import poplib import rfc822 import time from nettools import * lower = string.lower strip = string.strip find = string.find LF = '\n' CRLF = '\r\n' # Exception class class POPMboxError(Exception): pass # the mail gateway class POPMbox: """A POP3 --> mailbox gateway. Retrieves mail messages from a POP3 account and passes them on to a Unix mailbox file.""" version = 'POPMbox 1.0' # 1.0/19990303/bb: initial release def __init__(self): self.localhost = localhost() # this host's FQDN self.mbox = '' # Mailbox file name to write self.fp = None # Mailbox file object self.pop_host = '' # POP3 server to get messages from self.pop_user = '' # POP3 user name self.pop_pass = '' # POP3 password self.pop_dele = 0 # delete mail after reading? self.pop = None # poplib.POP3 object def banner(self): return '%s starting on %s' % (self.version, curtime()) def config_mbox(self, mbox): self.mbox = mbox def config_pop(self, phost, puser, ppass, dele = 1): self.pop_host = phost self.pop_user = puser self.pop_pass = ppass self.pop_dele = dele def gateway(self, msg): """take the message msg, which is a list of strings, and append it to self.fp""" EOF = '\x1A' # append to the file try: self.fp.write('From - ' + time.ctime(time.time()) + LF) for line in msg: if line[:2] == '..': line = line[1:] # drop duplicate leading periods elif lower(line[:5]) == 'from ': line = '>' + line # but protect unprotected "from " lines line = string.replace(line, EOF, '') # delete ^Z characters (DOS EOF) line = string.expandtabs(line, 8) # expand TABs self.fp.write(line + LF) self.fp.write(LF) return 1 except IOError, e: print ' ! ', e return 0 def forward_all(self): """forward all waiting messages""" try: id = hdr = None msgs, bytes = self.pop.stat() if msgs < 1: return print '%s: %d (%d)' % (self.pop_user, msgs, bytes) msglist = self.pop.list()[1] for s in msglist: id = string.split(s)[0] # message id on POP server hdr = self.pop.top(id, 0)[1] # get header mail = self.pop.retr(id)[1] # get message if self.gateway(mail) and self.pop_dele: self.pop.dele(id) id = hdr = None except poplib.error_proto, msg: print ' !!! forward_all:', msg, id and '(msg id %s)' % id or '' if hdr: print fmtlist(hdr, lambda h: ' ! ' + h) except socket.error, msg: print ' !!! forward_all:', sockerror(msg), id and '(msg id %s)' % id or '' if hdr: print fmtlist(hdr, lambda h: ' ! ' + h) def connect_pop(self): try: self.pop = poplib.POP3(self.pop_host) return 1 except socket.error, msg: print ' !!! connect_pop(%s):' % self.pop_host, sockerror(msg) self.pop = None return 0 except poplib.error_proto, msg: print ' !!! connect_pop(%s):' % self.pop_host, msg self.pop = None return 0 def login_pop(self): try: self.pop.user(self.pop_user) self.pop.pass_(self.pop_pass) return 1 except socket.error, msg: print ' !!! login_pop(%s):' % self.pop_host, sockerror(msg) return 0 except poplib.error_proto, msg: print ' !!! login_pop(%s):' % self.pop_host, msg return 0 def disconnect_pop(self): if self.pop: try: self.pop.quit() except: pass self.pop = None def check(self): """check the POP3 mailbox and forward all waiting messages""" try: self.fp = open(self.mbox, 'a') except IOError, msg: print msg[1] return if self.connect_pop(): if self.login_pop(): self.forward_all() self.disconnect_pop() self.fp.close() self.fp = None # end class POPMbox def check(gw, pop): """check one pop account""" # go do it gw.config_mbox(pop[3]) gw.config_pop(pop[0], pop[1], pop[2], pop[4]) gw.check() def check_multi(pop_accounts): gw = POPMbox() print gw.banner() for pop in pop_accounts: check(gw, pop) print '-' * 20 def main(): """A mail gateway for dware. Retrieves mails from the dware project management POP3 accounts and passes them on to a Unix mailbox file. WARNING: This function contains clear-text passwords!""" import sys, os sys.stderr = sys.stdout # tracebacks on stdout! mboxdir = r'\\DWAS21\DO\Daten\PM\Mail_in\POP2Mbox' '\\' mbox = mboxdir + 'dware.mbx' dele = 1 accounts = [ # a list of (pop_host, pop_user, pop_pass, mbox, delete) tuples ('mail.intern.dware.ch', 'dwamhc', 'mhc', mbox, dele), # 2000-10-17/dwabb: NPO-Account auf Wunsch von dwaaw rausgenommen # ('mail.intern.dware.ch', 'dwanpo', 'npo', mbox, dele), ('mail.intern.dware.ch', 'dwainfo', 'info', mbox, dele), ] check_multi(accounts) if __name__ == '__main__': main()