Добавить поддержку SMTP AUTH в библиотеку Python smtpd... не можете переопределить метод?

Итак, я хотел расширить класс SMTPServer для Python smtpd, чтобы он мог обрабатывать подключения SMTP AUTH. Казалось, достаточно просто...

Итак, я выглядел так, как будто я мог начать вот так:

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

Но по какой-то причине это никогда не вызывается. Библиотека Python smtpd вызывает другие подобные методы:

        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)

Почему это не вызовет мой метод?

После этого я подумал, что мог бы просто переопределить весь метод found_terminator(self):, но это тоже не сработало.

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

Я делаю что-то глупое или...? Может быть, я просто еще не проснулся сегодня...

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 ответ

Решение

Вы должны продлить SMTPChannel - вот где smtp_реализованы методы глагола; ваше расширение SMTPServer просто нужно вернуть свой собственный подкласс канала.

TL&DR: чтобы добавить дополнительные функции в SMTPChannel, вам просто нужно объявить функцию, а затем добавить ее непосредственно в smtpd.SMTPChannel

Объяснение:

Класс SMTPChannel предназначен для ответа на команды, которые вводит пользователь на открытом порту (обычно это порт 25). То, как он ищет команды, на которые он может ответить, основано на "Самоанализе", где он проверяет все доступные атрибуты функции.

Обратите внимание, что функции в SMTPChannel должны начинаться с "smtp_". Например, если вы хотите ответить на HELP, вы должны создать smtpd.SMTPChannel.smtp_HELP.

Функция ниже взята из исходного кода, который детализирует самоанализ

class SMTPChannel(asynchat.async_chat):
  method = getattr(self, 'smtp_' + command, None)

CodeThatWorks

Шаг 1: объявить функцию, которая будет вызываться

def smtp_HELP(self,arg):
  self.push("[8675309] GPT Answers to HELP")

Шаг 2: Добавьте следующую функцию в smtpd.SMTPChannel

class FakeSMTPServer(smtpd.SMTPServer):

"""A Fake smtp server"""
        smtpd.SMTPChannel.smtp_HELP = smtp_HELP

Шаг 3: Telnet к localhost 25 и тестирование

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 vics-imac.fios-router.home ESMTP Sendmail 6.7.4 Sunday 17 March 2019
HELP
[8675309] GPT Answers to HELP
Другие вопросы по тегам