views:

242

answers:

1

So, I wanted to extend the Python smtpd SMTPServer class so that it could handle SMTP AUTH connections. Seemed simple enough...

So, it looked like I could just start like this:

def smtp_EHLO(self, arg):
    print 'got in arg: ', arg
    # do stuff here...

But for some reason, that never gets called. The Python smtpd library calls other similar methods like this:

        method = None
        i = line.find(' ')
        if i < 0:
            command = line.upper()
            arg = None
        else:
            command = line[:i].upper()
            arg = line[i+1:].strip()
        method = getattr(self, 'smtp_' + command, None)

Why won't it call my method?

After that, I thought that I could probably just override the entire found_terminator(self): method, but that doesn't seem to work either.

 def found_terminator(self):
     # I add this to my child class and it never gets called...

Am I doing something stupid or...? Maybe I just haven't woken up fully yet today...

import smtpd import asyncore

class CustomSMTPServer(smtpd.SMTPServer):

def smtp_EHLO(self, arg):

    print 'got in arg: ', arg

def process_message(self, peer, mailfrom, rcpttos, data):
    print 'Receiving message from:', peer
    print 'Message addressed from:', mailfrom
    print 'Message addressed to  :', rcpttos
    print 'Message length        :', len(data)
    print 'HERE WE ARE MAN!'
    return

# Implementation of base class abstract method
def found_terminator(self):
    print 'THIS GOT CALLED RIGHT HERE!'

    line = EMPTYSTRING.join(self.__line)
    print >> DEBUGSTREAM, 'Data:', repr(line)
    self.__line = []
    if self.__state == self.COMMAND:
        if not line:
            self.push('500 Error: bad syntax')
            return
        method = None
        i = line.find(' ')
        if i < 0:
            command = line.upper()
            arg = None
        else:
            command = line[:i].upper()
            arg = line[i+1:].strip()
        method = getattr(self, 'smtp_' + command, None)

        print 'looking for: ', command
        print 'method is: ', method

        if not method:
            self.push('502 Error: command "%s" not implemented' % command)
            return
        method(arg)
        return
    else:
        if self.__state != self.DATA:
            self.push('451 Internal confusion')
            return
        # Remove extraneous carriage returns and de-transparency according
        # to RFC 821, Section 4.5.2.
        data = []
        for text in line.split('\r\n'):
            if text and text[0] == '.':
                data.append(text[1:])
            else:
                data.append(text)
        self.__data = NEWLINE.join(data)
        status = self.__server.process_message(self.__peer,
                                               self.__mailfrom,
                                               self.__rcpttos,
                                               self.__data)
        self.__rcpttos = []
        self.__mailfrom = None
        self.__state = self.COMMAND
        self.set_terminator('\r\n')
        if not status:
            self.push('250 Ok')
        else:
            self.push(status)

server = CustomSMTPServer(('127.0.0.1', 1025), None)

asyncore.loop()

+1  A: 

You need to extend SMTPChannel -- that's where the smtp_verb methods are implemented; your extension of SMTPServer just needs to return your own subclass of the channel.

Alex Martelli
Gah, apparently I *am* asleep today. Thanks!
Keith Palmer