Mercurial > smtpserver
view smtpserver.py @ 4:87317bd93890 default tip
The server now has a separate thread that forwards queued mail to an external server.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Tue, 18 Mar 2008 22:25:31 -0500 |
parents | e033c476f97a |
children |
line wrap: on
line source
import os import sys import smtpd import smtplib import asyncore import grp import pwd import logging import traceback import threading import Queue class MockSMTP( object ): def __init__( self, server, port ): pass def login( self, username, password ): pass def sendmail( self, mailfrom, rcpttos, data ): pass def quit( self ): pass def mailThread( queue, config, smtpClass ): done = False try: while not done: item = queue.get() if item["cmd"] == "quit": logging.info( "quit signal received, exiting." ) done = True elif item["cmd"] == "sendmsg": # TODO: If the sending of the message fails, we should # try to re-queue it and re-send it later. logging.info( "sending message from %s to %s" % ( item["mailfrom"], item["rcpttos"] ) ) server = smtpClass( config.server, config.port ) server.login( config.username, config.password ) server.sendmail( item["mailfrom"], item["rcpttos"], item["data"] ) server.quit() logging.info( "done." ) else: raise AssertionError( "Bad cmd: %s" % item["cmd"] ) except: logging.error( "exception in mailThread()." ) logging.error( traceback.format_exc() ) class MyServer( smtpd.SMTPServer ): import smtpconfig as config def __init__( self, smtpClass ): self.smtpClass = smtpClass self.queue = Queue.Queue() smtpd.SMTPServer.__init__( self, self.config.my_addr, None ) def bind( self, addr ): retval = smtpd.SMTPServer.bind( self, addr ) gid = grp.getgrnam( self.config.gid )[2] uid = pwd.getpwnam( self.config.uid )[2] os.setgid( gid ) os.setuid( uid ) logging.info( "Bound to %s and changed user to %s." % ( addr, self.config.uid ) ) self.mailThread = threading.Thread( target = mailThread, args = (self.queue, self.config, self.smtpClass) ) self.mailThread.start() return retval def finalize( self ): self.queue.put( {"cmd" : "quit"} ) def process_message( self, peer, mailfrom, rcpttos, data ): if peer[0] != "127.0.0.1": logging.warn( "not from localhost: %s" % peer ) return if not self.mailThread.isAlive(): logging.info( "mailThread is no longer alive! exiting." ) raise asyncore.ExitNow() logging.info( "queuing message from %s to %s on %s (length %d)." % (mailfrom, rcpttos, peer, len(data)) ) self.queue.put( { "cmd" : "sendmsg", "mailfrom" : mailfrom, "rcpttos" : rcpttos, "data" : data } ) if __name__ == "__main__": if os.getuid() != 0: print "This program must be run as root." sys.exit( -1 ) logging.basicConfig( filename = "smtpserver.log", format = "%(asctime)-15s %(levelname)s: %(message)s", level = logging.INFO ) if len( sys.argv ) == 2 and sys.argv[1] == "test": msg = "Test mode enabled." logging.info( msg ) print msg smtpClass = MockSMTP else: smtpClass = smtplib.SMTP server = MyServer( smtpClass ) msg = "Listening for incoming connections on port %s." % \ server.config.my_addr[1] logging.info( msg ) print msg try: asyncore.loop() finally: server.finalize()