import asynchat, asyncore, socket import pwd, os, sys, logging, logging.handlers import mailbox, email class SMTPChannel(asynchat.async_chat): def __init__(self, server, sock, addr): asynchat.async_chat.__init__(self, sock) self.server = server self.set_terminator("\n") self.data = "" self.read_data = False def collect_incoming_data(self, data): self.data += data if self.data.__len__() > 16384: print "too much data, shutdown" self.close_when_done() def found_terminator(self): if self.read_data: if self.data.endswith("\n."): self.push("250 Ok: queued as 12345\n") self.read_data = False mail = email.message_from_string(self.data) key=self.server.maildir.add(mail) self.server.logger.info("New Mail: %s" % key) self.server.maildir.flush() self.data = "" else: self.data += "\n" elif self.data.startswith("EHLO") \ or self.data.startswith("HELO"): self.push("HELO there\n") self.data = "" elif self.data.startswith("DATA"): self.push("354 End data with .\n") self.read_data = True self.data="" elif self.data.startswith("QUIT"): self.data = "" self.push("221 Bye\n") self.close_when_done() else: self.push("250 OK\n") self.data = "" class SMTPServer(asyncore.dispatcher): def __init__(self): asyncore.dispatcher.__init__(self) self.port = 25 self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind(("", self.port)) self.listen(5) self.maildir = mailbox.Maildir("Maildir", create=True) self.logger = logging.getLogger('MyLogger') self.logger.setLevel(logging.DEBUG) handler = logging.handlers.TimedRotatingFileHandler("log/smtp.log", "D", 1) self.logger.addHandler(handler) self.logger.info("Startup; pid=%s" % os.getpid()) def handle_accept(self): conn, addr = self.accept() self.logger.info("New Client %s" % addr) SMTPChannel(self, conn, addr) if __name__ == '__main__': s = SMTPServer() #user change pwinfo = pwd.getpwnam('nobody') os.setregid(pwinfo[3],pwinfo[3]) os.setreuid(pwinfo[2],pwinfo[2]) #"Robustly turn into a UNIX daemon, running in our_home_dir." # First fork try: pid = os.fork() if pid > 0: print "PID: %s" % pid sys.exit(0) # kill off parent except OSError, e: sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror)) sys.exit(1) os.setsid() os.chdir('/') os.umask(0) # Second fork try: if os.fork() > 0: os._exit(0) except OSError, e: sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror)) os._exit(1) si = open('/dev/null', 'r') so = open('/dev/null', 'a+', 0) se = open('/dev/null', 'a+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # Set custom file descriptors so that they get proper buffering. sys.stdout, sys.stderr = so, se asyncore.loop()