如何在smtpd.SMTPServer.process_message中拒绝收件人?

问题描述 投票:1回答:3

假设您在重写的类中处理消息,例如:

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)最终会放弃,并在几小时后警告用户。 documentation看起来很稀疏。

python email smtp
3个回答
5
投票

正如the sources中记载的那样(对不起!),process_message的规格包括:

对于正常的“250 Ok”响应,此函数应返回None;否则它以RFC 821格式返回所需的响应字符串。

所以你可以“返回'554个坏收件人%s'%badrecipients”而不是使用那个raise声明 - 不完全令人满意(没有正确解释好坏的混合,RFC 821应该返回'250 Ok '但也会在稍后发送警告邮件)但它似乎确实是你正在寻找的raise“立即反弹”效果。


1
投票

拒绝消息的方法是返回一个包含process_message方法错误代码的字符串;例如

return '550 No such user here'

但是,RFC 821不允许在传输消息数据后返回错误代码550(它应该在RCPT命令之后返回),并且遗憾的是smtpd模块不提供返回错误代码的简单方法。那个阶段。此外,smtpd.py通过使用自动修改“私有”双下划线属性使其类的子类化变得困难。

您可以使用以下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
投票

以下将丢弃邮件而不反弹。

return '554-5.7.1'

问题:如果您在没有弹跳的情况下拒绝邮件,发件人MTA将尝试一次又一次地重新发送邮件。

错误代码550将退回电子邮件,这可能是一个坏主意,因为您不希望给予spamer任何有关您的邮件服务器的信息。小心一点。

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
© www.soinside.com 2019 - 2024. All rights reserved.