Thursday October 23, 2008 at 22:49
Subject: So you want to process e-mail from Python?
Keywords:
E-mail, Python, Technical
Posted by: Sean Reifschneider
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:
(Post Reply)
-
Report if a Traceback happens.
Give the system administrator the opportunity to correct
Tracebacks and re-process the message before bouncing it.
Log errors and tracebacks.
Parse the incoming message.
Report success when the message is completely processed.
- #!/usr/bin/env python
- #
- # Python program which receives e-mail.
- import rfc822, syslog, sys, random, os
- #################
- class ExceptHook:
- ########################################################################
- def __init__(self, useSyslog = 1, useStderr = 0, emailRecipient = None):
- self.useSyslog = useSyslog
- self.useStderr = useStderr
- self.useEmail = emailRecipient
- #######################################
- def __call__(self, etype, evalue, etb):
- import traceback, string
- tb = traceback.format_exception(*(etype, evalue, etb))
- tb = map(string.rstrip, tb)
- tb = string.join(tb, '\n')
- if self.useEmail:
- emailFp = os.popen('/usr/sbin/sendmail -t -oi', 'w')
- emailFp.write('To: %s\n' % self.useEmail)
- emailFp.write('From: %s\n' % self.useEmail)
- emailFp.write('Subject: Traceback notification from %s\n' %
- os.path.basename(sys.argv[0]))
- emailFp.write('\n')
- else: emailFp = None
- for line in string.split(tb, '\n'):
- if emailFp: emailFp.write(line + '\n')
- if self.useSyslog: syslog.syslog(line)
- if self.useStderr: sys.stderr.write(line + '\n')
- if emailFp: emailFp.close()
- sys.stderr.write('Error in processing e-mail.\n')
- # TEMPFAIL causes the delivery to be retried
- sys.exit(os.EX_TEMPFAIL)
- #################################
- # logging and exception handling
- syslog.openlog(os.path.basename(sys.argv[0]), syslog.LOG_PID, syslog.LOG_MAIL)
- sys.excepthook = ExceptHook(useSyslog = 1, useStderr = 0,
- emailRecipient = 'user@example.com')
- # parse the incoming message
- #(For Python versions <2.4)
- #import rfc822
- #headers = rfc822.Message(sys.stdin)
- #(For Python versions >= 2.4)
- import email.parser
- headers = email.parser.Parser().parse(sys.stdin)
- # process the message here
- syslog.syslog('Received mail from "%s", subject: "%s"' % (
- headers.get('From'), headers.get('Subject') ))
- # demonstration of what happens when there's an error
- # generate an error 50% of the time
- if random.choice([ True, False ]): raise NotImplementedError('Test exception')
- # successful return code
- sys.exit(0)
(Post Reply)