By Sean Reifschneider Date 2008-10-23 22:49 Tags e-mail, python, sean reifschneider, technical
The other day I had two different clients asking about processing e-mail from a python program. In particular, each e-mail message that comes in gets handed off to be processed by this program. Setting up the mail server to call the program is fairly easy, by configuring local delivery and using the .forward file or similar. However, the program which processes the message needs to do a number of things to do it's job reliably.
I pulled together some pieces of existing code I had to handle these issues. Read on for an example of my code for processing e-mail.
The main responsibilities that need to be handled are:
This sample includes the ability to report tracebacks via syslog directly, by providing information back to the mail server (via stderr, which many mail servers honor), and by e-mailing a traceback report.
Below is the code I came up with, the highlighted portion is where the custom processing would be done.
This source can be downloaded from the ftp.tummy.com FTP site under /pub/tummy/pythonmailrcpt. This code is placed in the public domain, feel free to use it.
Mail processing example:
 _place_holder;
import rfc822, syslog, sys, random, os
 _place_holder;
 _place_holder;
class ExceptHook:
 _place_holder;  _place_holder;########################################################################
 place_holder;  _place_holder;def __init_(self, useSyslog = 1, useStderr = 0, emailRecipient = None):
 _place_holder;  _place_holder;  _place_holder; self.useSyslog = useSyslog
 _place_holder;  _place_holder;  _place_holder; self.useStderr = useStderr
 _place_holder;  _place_holder;  _place_holder; self.useEmail = emailRecipient
 _place_holder;
 _place_holder;
 _place_holder;  _place_holder;#######################################
 place_holder;  _place_holder;def __call_(self, etype, evalue, etb):
 _place_holder;  _place_holder;  _place_holder; import traceback, string
 _place_holder;  _place_holder;  _place_holder; tb = traceback.format_exception(*(etype, evalue, etb))
 _place_holder;  _place_holder;  _place_holder; tb = map(string.rstrip, tb)
 _place_holder;  _place_holder;  _place_holder; tb = string.join(tb, '\n')
 _place_holder;
 _place_holder;  _place_holder;  _place_holder; if self.useEmail:
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;emailFp = os.popen('/usr/sbin/sendmail -t -oi', 'w')
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;emailFp.write('To: %s\n' % self.useEmail)
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;emailFp.write('From: %s\n' % self.useEmail)
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;emailFp.write('Subject: Traceback notification from %s\n' %
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;os.path.basename(sys.argv[0]))
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;emailFp.write('\n')
 _place_holder;  _place_holder;  _place_holder; else: emailFp = None
 _place_holder;
 _place_holder;  _place_holder;  _place_holder; for line in string.split(tb, '\n'):
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;if emailFp: emailFp.write(line + '\n')
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;if self.useSyslog: syslog.syslog(line)
 _place_holder;  _place_holder;  _place_holder;  _place_holder;  _place_holder;if self.useStderr: sys.stderr.write(line + '\n')
 _place_holder;  _place_holder;  _place_holder; if emailFp: emailFp.close()
 _place_holder;
 _place_holder;  _place_holder;  _place_holder; sys.stderr.write('Error in processing e-mail.\n')
 _place_holder;
 _place_holder;  _place_holder;  _place_holder; #  _place_holder;TEMPFAIL causes the delivery to be retried
 _place_holder;  _place_holder;  _place_holder; sys.exit(os.EX_TEMPFAIL)
 _place_holder;
syslog.openlog(os.path.basename(sys.argv[0]), syslog.LOG_PID, syslog.LOG_MAIL)
sys.excepthook = ExceptHook(useSyslog = 1, useStderr = 0,
 _place_holder;  _place_holder;  _place_holder; emailRecipient = 'user@example.com')
 _place_holder;
import email.parser
headers = email.parser.Parser().parse(sys.stdin)
 _place_holder;
syslog.syslog('Received mail from "%s", subject: "%s"' % (
 _place_holder;  _place_holder;  _place_holder; headers.get('From'), headers.get('Subject') ))
 _place_holder;
if random.choice([ True, False ]): raise NotImplementedError('Test exception')
 _place_holder;
sys.exit(0)