40 lines
1.3 KiB
Python
40 lines
1.3 KiB
Python
import smtpd
|
|
import email
|
|
import asyncore
|
|
import threading
|
|
|
|
class SMTPServer(smtpd.SMTPServer):
|
|
|
|
def __init__(self, addr='0.0.0.0', port=25):
|
|
super().__init__((addr, port), None)
|
|
self.listen_thread = None
|
|
self.verbose = False
|
|
self.on_message = None
|
|
self.is_running = True
|
|
|
|
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
|
|
if self.verbose:
|
|
print(f"SMTP IN: {peer=} {mailfrom=} {rcpttos=} {len(data)} bytes, extra:", kwargs)
|
|
if self.on_message and callable(self.on_message):
|
|
mail = email.message_from_bytes(data)
|
|
self.on_message(peer, mailfrom, rcpttos, mail)
|
|
|
|
def start(self):
|
|
if self.verbose:
|
|
print(f"SMTP server running on: {self._localaddr[0]}:{self._localaddr[1]}")
|
|
try:
|
|
while self.is_running:
|
|
asyncore.loop(timeout=1, use_poll=True)
|
|
except KeyboardInterrupt:
|
|
self.close()
|
|
|
|
def start_background(self):
|
|
self.listen_thread = threading.Thread(target=self.start)
|
|
self.listen_thread.start()
|
|
return self.listen_thread
|
|
|
|
def stop(self):
|
|
self.is_running = False
|
|
self.close()
|
|
if self.listen_thread:
|
|
self.listen_thread.join() |