-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New attempt at getting secure SMTP working
- Loading branch information
Murray Christopherson
committed
Apr 13, 2018
1 parent
af31dd1
commit f36e36e
Showing
5 changed files
with
163 additions
and
15 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import os | ||
import time | ||
import ssl | ||
|
||
from aiosmtpd.smtp import SMTP as Server, syntax | ||
from aiosmtpd.controller import Controller | ||
|
||
SMTP_PORT = int(os.environ.get(u'SMTP_PORT', u'8080')) | ||
SECURE_SMTP_PORT = int(os.environ.get(u'SECURE_SMTP_PORT', u'8081')) | ||
|
||
|
||
class MyController(Controller): | ||
def factory(self): | ||
return MyServer(self.handler) | ||
|
||
class MyServer(Server): | ||
pass | ||
|
||
class MyHandler: | ||
async def handle_HELO(self, server, session, envelope, hostname): | ||
print(u'HELO entered') | ||
return None | ||
|
||
async def handle_EHLO(self, server, session, envelope, hostname): | ||
print(u'EHLO entered') | ||
return None | ||
|
||
async def handle_NOOP(self, server, session, envelope, arg): | ||
print(u'NOOP entered') | ||
return None | ||
|
||
async def handle_QUIT(self, server, session, envelope): | ||
print(u'QUIT entered') | ||
return None | ||
|
||
async def handle_VRFY(self, server, session, envelope, address): | ||
print(u'VRFY entered') | ||
return None | ||
|
||
async def handle_MAIL(self, server, session, envelope, address, mail_options): | ||
print(u'MAIL entered') | ||
return None | ||
|
||
async def handle_RCPT(self, server, session, envelope, address, rcpt_options): | ||
print(u'RCPT entered') | ||
return None | ||
|
||
async def handle_RSET(self, server, session, envelope): | ||
print(u'RSET entered') | ||
return None | ||
|
||
async def handle_DATA(self, server, session, envelope): | ||
print(u'DATA entered') | ||
return None | ||
|
||
async def handle_STARTTLS(self, server, session, envelope): | ||
print(u'STARTTLS entered') | ||
return True | ||
|
||
async def handle_exception(self, error): | ||
print(u'exception entered') | ||
return u'542 Internal server error' | ||
|
||
_controller = None | ||
def smtp_server_start(): | ||
global _controller | ||
if _controller is None: | ||
_controller = MyController(MyHandler(), hostname=u'localhost', port=SMTP_PORT) | ||
_controller.start() | ||
time.sleep(1.0) | ||
|
||
class MySecureController(Controller): | ||
def factory(self): | ||
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) | ||
return MyServer(self.handler, tls_context=context, require_starttls=True) | ||
|
||
class MySecureServer(Server): | ||
async def smtp_AUTH(self, *args, **kwargs): | ||
print(u'AUTH entered: {}\n{}'.format(args, kwargs)) | ||
await self.push(u'250 OK') | ||
|
||
class MySecureHandler: | ||
async def handle_HELO(self, server, session, envelope, hostname): | ||
print(u'HELO entered') | ||
return None | ||
|
||
async def handle_EHLO(self, server, session, envelope, hostname): | ||
print(u'EHLO entered') | ||
return None | ||
|
||
async def handle_NOOP(self, server, session, envelope, arg): | ||
print(u'NOOP entered') | ||
return None | ||
|
||
async def handle_QUIT(self, server, session, envelope): | ||
print(u'QUIT entered') | ||
return None | ||
|
||
async def handle_VRFY(self, server, session, envelope, address): | ||
print(u'VRFY entered') | ||
return None | ||
|
||
async def handle_MAIL(self, server, session, envelope, address, mail_options): | ||
print(u'MAIL entered') | ||
return None | ||
|
||
async def handle_RCPT(self, server, session, envelope, address, rcpt_options): | ||
print(u'RCPT entered') | ||
return None | ||
|
||
async def handle_RSET(self, server, session, envelope): | ||
print(u'RSET entered') | ||
return None | ||
|
||
async def handle_DATA(self, server, session, envelope): | ||
print(u'DATA entered') | ||
return None | ||
|
||
async def handle_STARTTLS(self, server, session, envelope): | ||
print(u'STARTTLS entered') | ||
return True | ||
|
||
async def handle_exception(self, error): | ||
print(u'exception entered') | ||
return u'542 Internal server error' | ||
|
||
_secure_controller = None | ||
def secure_smtp_server_start(): | ||
global _secure_controller | ||
if _secure_controller is None: | ||
_secure_controller = MySecureController(MySecureHandler(), hostname=u'localhost', port=u'') | ||
_secure_controller.start() | ||
time.sleep(1.0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,36 @@ | ||
import unittest | ||
|
||
from quick_email import send_email | ||
import smtpd_fake | ||
|
||
try: | ||
import aiosmtpd | ||
del aiosmtpd | ||
import tests.smtp.aiosmtpd_fake as smtp | ||
|
||
_can_run_ssl_tests = True | ||
_can_run_auth_tests = True | ||
except ImportError: | ||
except (ImportError, SyntaxError): | ||
import tests.smtp.smtpd_fake as smtp | ||
_can_run_ssl_tests = False | ||
_can_run_auth_tests = False | ||
|
||
class TestQuickEmail(unittest.TestCase): | ||
def test_send_email(self): | ||
smtpd_fake.smtp_server_thread() | ||
send_email(u'localhost', smtpd_fake.SMTP_PORT, u'Example <example@example.com>', u'The Subject', send_to=u'Test <test@test.com>', send_cc=None, send_bcc=None, plain_text=u'Some Text', html_text=u'<b>Some Bold Text</b>', attachment_list=None, inline_attachment_dict=None) | ||
smtp.smtp_server_start() | ||
send_email(u'localhost', smtp.SMTP_PORT, u'Example <example@example.com>', u'The Subject', send_to=u'Test <test@test.com>', plain_text=u'Some Text', html_text=u'<b>Some Bold Text</b>') | ||
|
||
@unittest.skipUnless(_can_run_ssl_tests, 'SSL tests unsupported') | ||
def test_send_email_ssl(self): | ||
pass | ||
smtp.secure_smtp_server_start() | ||
send_email(u'localhost', smtp.SECURE_SMTP_PORT, u'Example <example@example.com>', u'The Subject', send_to=u'Test <test@test.com>', plain_text=u'Some Text', html_text=u'<b>Some Bold Text</b>', ssl=True) | ||
|
||
@unittest.skipUnless(_can_run_auth_tests, 'Auth tests unsupported') | ||
def test_send_email_auth(self): | ||
pass | ||
smtp.secure_smtp_server_start() | ||
send_email(u'localhost', smtp.SECURE_SMTP_PORT, u'Example <example@example.com>', u'The Subject', send_to=u'Test <test@test.com>', plain_text=u'Some Text', html_text=u'<b>Some Bold Text</b>', username=u'testuser', password=u'password') | ||
|
||
@unittest.skipUnless(_can_run_ssl_tests and _can_run_auth_tests, 'SSL or Auth tests unsupported') | ||
def test_send_email_ssl_auth(self): | ||
pass | ||
smtp.secure_smtp_server_start() | ||
send_email(u'localhost', smtp.SECURE_SMTP_PORT, u'Example <example@example.com>', u'The Subject', send_to=u'Test <test@test.com>', plain_text=u'Some Text', html_text=u'<b>Some Bold Text</b>', username=u'testuser', password=u'password', ssl=True) | ||
|
||
if __name__ == u'__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters