Skip to content

Instantly share code, notes, and snippets.

@jondkelley
Last active September 19, 2018 01:00
Show Gist options
  • Save jondkelley/5d3c0eae245d3b0b16b032e27608af48 to your computer and use it in GitHub Desktop.
Save jondkelley/5d3c0eae245d3b0b16b032e27608af48 to your computer and use it in GitHub Desktop.
Example of how to overload custom SMTP commands in asyncio smtp server in python3 (no proxy or mailbox capability shown)
#!/usr/bin/env python3
# pip3 install aiosmtpd
import asyncio
from aiosmtpd.controller import Controller
from aiosmtpd.handlers import AsyncMessage
from aiosmtpd.smtp import SMTP, syntax
import logging
import uuid
import logging
__version__ = "0.0.1"
__metarealease__ = "alpha"
class SMTPOverload(SMTP):
"""
overloads homebrew smtp commands
"""
@syntax('TEST value')
async def smtp_TEST(self, value):
"""
smtp test command
"""
if not 'alpha' in __metarealease__:
help = "501 Command not implemented"
await self.push(help)
return
elif not value:
await self.push('501 Syntax: TEST value')
return
prefix="211"
if value == ".":
help = ("{prefix} it works\n"
"{prefix} congratulations").format(prefix=prefix)
await self.push(help)
return
elif value == "die":
logging.info("{prefix} test die issued; simulating hard physical crash".format(prefix=prefix))
help = ("503 simulate hard process crash\n"
"503 thanks for all the fish").format(prefix=prefix)
await self.push(help)
exit(0)
else:
await self.push('501 invalid test code')
return
status = await self._call_handler_hook('TEST', value)
await self.push(status)
class SMTPControllerOverload(Controller):
"""
overloads custom smtp controller functionality
"""
def factory(self):
"""
overload MySMTP and ident=
"""
_ver = __version__
_meta = __metarealease__.upper()
return SMTPOverload(self.handler, enable_SMTPUTF8=self.enable_SMTPUTF8, ident="SMTP Digester v{} ({})".format(_ver, _meta))
class MessageOverload(AsyncMessage):
"""
overloads attributes to get active access with envelopes / incoming data
you can proxy, store or forward if you wanna
"""
def __init__(self, message_class=None, *, loop=None):
super().__init__(message_class)
self.loop = loop or asyncio.get_event_loop()
async def handle_DATA(self, server, session, envelope):
self.t_uid = str(uuid.uuid4())[:8]
message = self.prepare_message(session, envelope)
await self.handle_message(message, envelope)
return '250 OK transaction defined t_uid={}'.format(self.t_uid)
async def handle_message(self, message, envelope):
"""
perform action on any elements of the incoming email
"""
print(self.t_uid)
print(message)
print(envelope.mail_from)
print(envelope.rcpt_tos)
print(envelope.rcpt_options)
print(envelope.smtp_utf8)
async def amain(loop):
"""
main loop everyone
"""
control = SMTPControllerOverload(MessageOverload(), hostname='', port=8025)
control.start()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
loop = asyncio.get_event_loop()
loop.create_task(amain(loop=loop))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment