pythonsslsmtpsmtpsaiosmtpd

How to create a working SMTPS server on port 465 using Python?


I'm trying to set up an SMTPS server on port 465 using Python and the aiosmtpd library. While I can connect to the server locally using openssl s_client, external mail servers (like Gmail) are unable to connect, reporting a "Connection refused" error.

Here's my current code:

import asyncio
import ssl
from aiosmtpd.controller import Controller
from aiosmtpd.handlers import Debugging

async def main():
    ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    ssl_context.load_cert_chain(
        certfile='./certs/fullchain.pem',
        keyfile='./certs/privkey.pem'
    )

    controller = Controller(
        handler=Debugging(),
        hostname='0.0.0.0',
        port=465,
        ssl_context=ssl_context
    )

    controller.start()
    print("SMTPS server started on port 465...")

    try:
        await asyncio.sleep(3600)
    finally:
        controller.stop()

if __name__ == "__main__":
    asyncio.run(main())

Though it works fine when I disable TLS encryption and change port number to 25.

I've verified that:

  1. The server starts without errors.
  2. I can connect to my server using openssl s_client -connect my_domain.example.com:465.
  3. The port 465 is open in my firewall.
  4. The SSL certificates are valid and match the domain name.

I know that there is also SMTP with STARTTLS protocol on port 587, but in my specific use case I need exactly SMTPS on port 465.

Additional information:

Python version: 3.12.3. OS: Ubuntu 24 server

Any help or guidance would be greatly appreciated. Thank you


Solution

  • ... external mail servers (like Gmail) are unable to connect, reporting a "Connection refused" error. ... Though it works fine when I disable TLS encryption and change port number to 25.

    External email servers always connect to port 25. Specifically they do a DNS MX lookup and then connect to port 25 on the given server. And since you don't have a server on port 25 this will result in "Connection refused". There is no way to specify a different port they should use.

    In other words: you can do nothing in your code to make it work, simply because the connecting mail server will not try to use your server on port 465. Port 465 and 587 are instead for user agents (MUA), not for mail servers (MTA).

    Also, port 25 actually supports TLS - using STARTTLS the same way as done with port 587.