Python smtpd ライブラリに SMTP AUTH サポートを追加…メソッドをオーバーライドできませんか?
質問
そこで、Python smtpd SMTPServer クラスを拡張して、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()
解決
あなたはSMTPChannel
を拡張する必要がある - smtp_
verbメソッドが実装されているところです。 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)
コードザットワークス
ステップ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:localhost 25 に Telnet してテストしてみる
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