I have the following server taken almost directly from the aiosmtpd docs:
import asyncio
import ssl
from aiosmtpd.controller import Controller
class ExampleHandler:
async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
if not address.endswith('@example.com'):
return '550 not relaying to that domain'
envelope.rcpt_tos.append(address)
return '250 OK'
async def handle_DATA(self, server, session, envelope):
print(f'Message from {envelope.mail_from}')
print(f'Message for {envelope.rcpt_tos}')
print(f'Message data:\n{envelope.content.decode("utf8", errors="replace")}')
print('End of message')
return '250 Message accepted for delivery'
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
controller = Controller(ExampleHandler(), port=8026, ssl_context=context)
controller.start()
input('Press enter to stop')
controller.stop()
However, when I start this server and try to send an email to it using swaks:
echo 'Testing' | swaks --to [email protected] --from "[email protected]" --server localhost --port 8026 -tls
It times out after 30s. If I remove the ssl_context=context from the server and -tls from the client then it sends the mail fine.
Additionally, when I try to connect via telnet and just send EHLO whatever then the server actually closes the connection.
What's the correct way to implement an aiosmtpd server that supports tls?
Building upon Wayne's own answer, here's how to create a STARTTLS server with aiosmtpd.
1. Create an SSL context
For testing, use the following command to generate a self-signed certificate for
localhost:openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=localhost'Load it into Python using the
sslmodule:2. Pass SSL context to aiosmtpd
Create a subclass of aiosmtpd's Controller that passes this context as the
tls_contexttoSMTP:3. Run it
Instantiate this controller with a handler and start it. Here, I use aiosmtpd's own
Debugginghandler:4. Test it
Either configure a local mail client to send to
localhost:1025, or useswaks:swaks -tls -t test --server localhost:1025... or use
openssl s_clientto talk to the server after the initialSTARTTLScommand has been issued:openssl s_client -crlf -CAfile cert.pem -connect localhost:1025 -starttls smtpThe full code
The code below additionally tests the server using swaks, and it also shows how to create a TLS-on-connect server (as in Wayne's answer).