質問

次のようなオーバーライドされたクラスでメッセージを処理するとしましょう:

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)は最終的にあきらめて、何時間も後にユーザーに警告します。 ドキュメントはかなりまばらに見えます。

役に立ちましたか?

解決

ソース(申し訳ありません!)、 process_message の仕様には以下が含まれます:

  

この関数はNoneを返すべきです。   通常の「250 Ok」応答。さもないと   目的の応答文字列を返します   RFC 821形式。

「554悪い受信者%s」%badrecipientsを返すことができます」その raise ステートメントを使用する代わりに、完全に満足のいくものではありません(RFC 821により「250 Ok」を返すべきである善と悪の混在を適切に説明していません)後で警告メールを送信することもできます)が、「すぐに返送する」ようです。 raise で探している効果。

他のヒント

メッセージを拒否する方法は、 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

以下は、メールをバウンスせずに破棄します。

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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top