Как отказаться от получателя в smtpd.SMTPServer.process_message? - PullRequest
1 голос
/ 23 июня 2009

Допустим, вы обрабатываете сообщение в переопределенном классе, например:

class MailProcessorServer(smtpd.SMTPServer):
  def process_message(self, peer, sender, rcpttos, data):
    badrecipients = []
    for rcpt in rcpttos:
      badrecipients.append(rcpt)

    #Here I want to warn the sender via a bounced email
    # that the recipient does not exist
    raise smtplib.SMTPRecipientsRefused(badrecipients)
    #but this just crashes the process and eventually the sender times out,
    # not good enough

Я просто хочу немедленно вернуться к отправителю. Вместо этого отправляющий сервис (скажем, GMail) просто в конце концов сдается и предупреждает пользователя много часов спустя. Документация кажется довольно скудной.

Ответы [ 3 ]

5 голосов
/ 23 июня 2009

Как указано только в источниках (извините!), Спецификации process_message включают в себя:

Эта функция должна возвращать None, для нормальный ответ «250 Ok»; иначе возвращает желаемую строку ответа в формате RFC 821.

Таким образом, вы могли бы «вернуть» 554 плохих получателей% s «% плохих получателей» вместо использования этого оператора raise - не совсем удовлетворительно (неправильно учитывается сочетание хороших и плохих, что в RFC 821 должен вернуть '250 Ok', но также отправить письмо с предупреждением позже), но это, похоже, эффект "немедленного возврата", который вы ищете с этим raise.

1 голос
/ 23 июня 2009

Способ отклонить сообщение - вернуть строку с кодом ошибки из вашего process_message метода; например,

return '550 No such user here'

Однако RFC 821 не позволяет возвращать код ошибки 550 после передачи данных сообщения (их следует возвращать после команды RCPT), а модуль smtpd, к сожалению, не обеспечивает простого способа вернуть код ошибки на этом этапе. Кроме того, smtpd.py затрудняет создание подклассов для своих классов, используя автоматическое изменение атрибутов "private" с двойным подчеркиванием.

Вы можете использовать следующие пользовательские подклассы классов smtpd, но я не тестировал этот код:

class RecipientValidatingSMTPChannel(smtpd.SMTPChannel):
    def smtp_RCPT(self, arg):
        print >> smtpd.DEBUGSTREAM, '===> RCPT', arg
        if not self._SMTPChannel__mailfrom:
            self.push('503 Error: need MAIL command')
            return
        address = self._SMTPChannel__getaddr('TO:', arg)
        if not address:
            self.push('501 Syntax: RCPT TO: <address>')
            return
        if self._SMTPChannel__server.is_valid_recipient(address):
            self._SMTPChannel__rcpttos.append(address)
            print >> smtpd.DEBUGSTREAM, 'recips:', self._SMTPChannel__rcpttos
            self.push('250 Ok')
        else:
            self.push('550 No such user here')


class MailProcessorServer(smtpd.SMTPServer):
    def handle_accept(self):
        conn, addr = self.accept()
        print >> smtpd.DEBUGSTREAM, 'Incoming connection from %s' % repr(addr)
        channel = RecipientValidatingSMTPChannel(self, conn, addr)

    def is_valid_recipient(self, address):
        # insert your own tests here, return True if it's valid
        return False
0 голосов
/ 27 апреля 2019

Следующее будет отбрасывать почту, не возвращая ее.

return '554-5.7.1'

Проблема: MTA отправителя будут пытаться пересылать почту снова и снова, если вы отклоняете почту без отказов.

Код ошибки 550 переадресует электронное письмо, что может быть плохой идеей, поскольку вы не хотите сообщать спамеру какую-либо информацию о вашем почтовом сервере. Будьте осторожны с этим.

return '550'

Обе ошибки приведут к smtplib.SMTPException. Вот упрощенный код, который я использую для обработки таких исключений.

try:
    if bounce:
        return '550 Bad address'
    else:
        self.send_and_quit(sender, recipients, data)
except smtplib.SMTPException as e:
    raise e
except Exception as e:
    # Catch any other exception
    logging.error(traceback.format_exc())

    if not isinstance(e, smtplib.SMTPException):
        self.send_and_quit(sender, recipients, data)
    else:
        raise e
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...