2009-06-22 68 views
1

比方说,你在被覆盖的类处理消息,如:如何拒绝smtpd.SMTPServer.process_message中的收件人?

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似乎很稀疏。

回答

5

由于只有在the sources记载(!对不起),process_message的规格包括:

这个函数应返回无,用于 普通的`250 OK“响应;否则返回 它以RFC 821格式返回所需的响应字符串 。

,所以你可以“回归‘554个坏收件人%s’的%badrecipients”,而不是使用raise声明 - 不完全令人满意(不正确地考虑好和坏的混合,其中由RFC 821 应该返回一个'250 Ok',但稍后也会发送一个警告邮件),但它似乎是您要用那raise寻找的“立即反弹”效果。

+1

+1的链接来源 – nalply 2011-05-17 07:45:13

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 
相关问题