Monitoring d’une boite IMAP en python

// juillet 29th, 2009 // Python

Voici un script en python qui permet de monitorer une boite mail via IMAP. Pour chaque nouveau mail contenant une pièce jointe, la pièce jointe est sauvegardée dans un sous-dossier ayant pour nom l’adresse mail de l’expéditeur. Le mail traité est sauvegardé dans un dossier IMAP nommé Backup. Ce script a été écrit en majorité par Suresh Kumar qu’on remercie au passage, j’ai ajouté un système de log avec rotation automatique ainsi quelques autres petites modifs.


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
import random
import string
import glob
import logging
import logging.handlers

AttachDir = 'Attachments'	    # Directory where Attachments will be stored
SaveAttachments = 1		    # Shall Attachements be saved ?
imap_server = "xxx.xxx.xxx.xxx"  # IP adress of IMAP Server
User = "user"		            # Username of the IMAP mailbox receiveing KDMs
Password = "passwd"		    # Password for the above mailbox
Do_sub=1                              # Shall the script create subdirectories entry for each sender e-mail
Do_backup = 1                       # Shall a backup directory be created in mailbox
IMAP_backup_Dir= "Backup"       # Name of the IMAP backup Directory
Frequency = 300		          # Time in seconds between two checks
exists = 0
name = 0
Do_random = 1
LOG_FILENAME = 'fichier_log.log'

my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=5242880, backupCount=4)
my_logger.addHandler(handler)

def dir_check_and_create(directory_name):
	try:
		exists = "0"
		curdir= os.getcwd()
		list = os.listdir(curdir)
		for name in list:
			if name == directory_name:
				exists = "1"
				break
		if exists != "1":
			os.mkdir(directory_name)

		exists == "0"

	except IOError, val:
		my_logger.debug('Unable to create "%s": %s' % (filename, str(val)))
		#error('Unable to create "%s": %s' % (filename, str(val)))

def write_file(filename, addr, data):
	if Do_random ==1:
		tmp_str = "".join(random.sample(string.letters+string.digits, 8))
		ext = os.path.splitext(filename)[1]
		file_name = tmp_str+ext
	else:
		file_name=filename
	if Do_sub ==1:
		os.chdir(addr)
		my_logger.debug('Writing '+filename+' as '+file_name+' in folder '+addr)
	else:
		my_logger.debug('Writing '+filename+' as '+file_name)
	fd = open(file_name, "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)
	my_logger.debug("Downloading file " + file + " sent by " + addr)
	#print "Downloading file " + file + " sent by " + addr
	#print "\n"
	path = os.path.join(AttachDir, file)
	path =file
	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]
			my_logger.debug("Error while decoding the attachmentfor message %s error: %s for %s ``%s''"
					% (msgnum, str(val), part.get_content_type(), filename))			

			#warn("Error while decoding the attachmentfor message %s error: %s for %s ``%s''"
					#    % (msgnum, str(val), part.get_content_type(), filename))
			continue

		if not data:
			my_logger.debug("Unable to decode the 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()
				os.chdir(AttachDir)
				list = os.listdir('.\\')
				if Do_sub ==1 :

					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)
				else:
					write_file(filename, addr, data)
					os.chdir(curdir)

			except IOError, val:
				my_logger.debug('Unable to cereate "%s": %s' % (filename, str(val)))

		count += 1

	return count

def process_message(text, msgnum):
	# Begin message processing
	try:
		msg = email.message_from_string(text)
	except email.Errors.MessageError, val:
		my_logger.debug("Error while processing message %s : %s" % (msgnum, str(val)))
		#warn("Error while processing message %s : %s" % (msgnum, str(val)))
		return text

	date = msg['Date'] or 'Tue, 09 Apr 1978 00:03: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]
		my_logger.debug('Unable to 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("Password not provided, please input one now 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':
		my_logger.debug('unable to open the INBOX folder for "%s" on "%s": %s' % (user, host, str(dat)))

	mbox.select('Inbox')
	typ, dat = mbox.search(None, 'ALL')

	if Do_backup == 1:
		mbox.create(IMAP_backup_Dir)

	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 mail with attachment found in INBOX"

	deleteme.sort()

	for number in deleteme:
		if Do_backup == 1:
			mbox.copy(number, 'Backup')

		mbox.store(number, "+FLAGS.SILENT", '(\\Deleted)')

	mbox.expunge()
	mbox.close()
	mbox.logout()

def main():
	dir_check_and_create(AttachDir)
	my_logger.debug("Monitoring IMAP server at " + imap_server + "  for mailbox  " + User)
	while 1:

		process_server(imap_server)
		printfre = str(Frequency)
		#my_logger.debug("Sleeping " + printfre + "  seconds...")
		sleep(Frequency)

if __name__ == '__main__':
	try:
		main()
	except KeyboardInterrupt:
		pass

Leave a Reply

You must be logged in to post a comment.