{"id":4872,"library":"aiosmtpd","title":"aiosmtpd - Asyncio-based SMTP Server","description":"aiosmtpd is an asyncio-based SMTP and LMTP server, providing an asynchronous, RFC 5321 compliant server that supports customizable extensions. It serves as a modern replacement for the deprecated `smtpd` module in the Python standard library. The current version is 1.4.6, and it's actively maintained under the aio-libs umbrella project.","status":"active","version":"1.4.6","language":"python","source_language":"en","source_url":"https://github.com/aio-libs/aiosmtpd","tags":["asyncio","smtp","email","server","mail","lmtp"],"install":[{"cmd":"pip install aiosmtpd","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Officially tested on CPython>=3.9 and PyPy>=3.9, though PyPI metadata states >=3.8. Future versions will drop Python 3.8 support.","package":"Python","optional":false}],"imports":[{"note":"The Controller class is in the 'controller' submodule.","wrong":"from aiosmtpd import Controller","symbol":"Controller","correct":"from aiosmtpd.controller import Controller"},{"note":"Directly using SMTP is possible but Controller is often preferred for managing the server in a separate thread.","symbol":"SMTP","correct":"from aiosmtpd.smtp import SMTP"},{"note":"Commonly used handler for testing, discards all incoming mail.","symbol":"handlers.Sink","correct":"from aiosmtpd.handlers import Sink"},{"note":"Default handler for the command-line script; prints incoming mail to stdout.","symbol":"handlers.Debugging","correct":"from aiosmtpd.handlers import Debugging"}],"quickstart":{"code":"import asyncio\nfrom aiosmtpd.controller import Controller\nfrom aiosmtpd.handlers import Debugging\nimport os\n\nasync def amain():\n    # Use Debugging handler to print incoming emails to console\n    handler = Debugging()\n    \n    # The Controller runs the SMTP server in a separate thread.\n    # For testing/quickstart, localhost:8025 is common.\n    controller = Controller(handler, hostname=os.environ.get('SMTP_HOST', '127.0.0.1'), port=int(os.environ.get('SMTP_PORT', 8025)))\n    \n    print(f\"Starting SMTP server on {controller.hostname}:{controller.port}...\")\n    controller.start()\n    print(\"SMTP server started. Press Ctrl+C to stop.\")\n    \n    try:\n        # Keep the main loop running while the controller's thread handles the SMTP server\n        await asyncio.Event().wait()\n    except asyncio.CancelledError:\n        pass\n    finally:\n        controller.stop()\n        print(\"SMTP server stopped.\")\n\nif __name__ == '__main__':\n    # Run the asyncio event loop\n    try:\n        asyncio.run(amain())\n    except KeyboardInterrupt:\n        print(\"Server interrupted by user.\")\n","lang":"python","description":"This quickstart sets up a basic SMTP server on `127.0.0.1:8025` using the `Debugging` handler, which prints all received emails to the console. It leverages `Controller` to run the server in a separate thread, allowing the main program to continue running or wait for interruption. You can connect to this server with any SMTP client (e.g., `smtplib` or `telnet`)."},"warnings":[{"fix":"Update `handle_NOOP(self, server)` to accept the `server` argument: `async def handle_NOOP(self, server): ...`","message":"The signature of the `handle_NOOP()` method in custom handlers changed from taking zero arguments to requiring a single argument in version 1.4.x. Custom handlers implementing this method must be updated.","severity":"breaking","affected_versions":">=1.4.0"},{"fix":"If clients connect without STARTTLS and require AUTH, initialize `Controller` or `SMTP` with `auth_require_tls=False`: `Controller(handler, ..., auth_require_tls=False)`.","message":"By default, the SMTP AUTH extension might not be advertised or supported by the server unless a STARTTLS command is issued first, or `auth_require_tls=False` is explicitly passed to the `Controller` or `SMTP` constructor. This can cause authentication failures with clients expecting immediate AUTH support.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Migrate `process_message()` logic to `async def handle_DATA(self, server, session, envelope): ...` ensuring it returns an SMTP response string (e.g., `'250 OK'`).","message":"The `process_message()` method in handler classes was deprecated. Implementations should now use the asynchronous `handle_DATA(self, server, session, envelope)` method for processing incoming mail data.","severity":"deprecated","affected_versions":"<1.0a5"},{"fix":"Replace `authentication_handler=my_func` with `authenticator=Authenticator(my_func)` (where `Authenticator` is imported from `aiosmtpd.smtp`).","message":"The `authentication_handler` parameter for the `SMTP` class constructor was deprecated in favor of `authenticator` and is scheduled for removal in version 2.0.","severity":"deprecated","affected_versions":">=1.3.0"},{"fix":"Adjust tests or application logic that rely on a specific short startup timeout, or explicitly set `ready_timeout` in the `Controller` constructor: `Controller(handler, ..., ready_timeout=1.0)`.","message":"The default `ready_timeout` for `Controller.start()` to wait for the SMTP server thread to become ready changed from 1 second to 5 seconds. This could impact testing setups or deployments sensitive to startup times.","severity":"gotcha","affected_versions":">=1.4.2"},{"fix":"Ensure your environment uses Python 3.9 or newer to guarantee compatibility with current and future `aiosmtpd` releases.","message":"While PyPI states `requires_python >=3.8`, the official documentation recommends CPython>=3.9 and PyPy>=3.9. The upcoming version 1.4.7 explicitly drops support for Python 3.8, requiring an upgrade if using newer `aiosmtpd` versions.","severity":"breaking","affected_versions":">=1.4.7 (future)"}],"env_vars":null,"last_verified":"2026-05-22T17:06:45.264Z","next_check":"2026-07-11T00:00:00.000Z","problems":[{"fix":"Install the package using pip: 'pip install aiosmtpd'.","cause":"The 'aiosmtpd' package is not installed in the Python environment.","error":"ModuleNotFoundError: No module named 'aiosmtpd'"},{"fix":"Upgrade 'setuptools' to at least version 46.4.0: 'pip install --upgrade setuptools'.","cause":"An outdated version of 'setuptools' is being used, which lacks support for the 'public' module required by 'aiosmtpd'.","error":"ModuleNotFoundError: No module named 'public'"},{"fix":"Install the package using pip: 'pip install aiosmtpd'.","cause":"The 'aiosmtpd' package is not installed in the Python environment.","error":"ImportError: No module named 'aiosmtpd'"},{"fix":"Ensure no other process is listening on the desired port. You can either choose a different port for your `aiosmtpd` server or terminate the process currently occupying the port. For development, you can often add `sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)` (though `aiosmtpd`'s `Controller` usually handles this; checking for an actively running process is the primary solution).","cause":"This error occurs when the `aiosmtpd` server attempts to bind to a network address (IP and port) that is already being used by another process on your system.","error":"OSError: [Errno 98] Address already in use"},{"fix":"When initializing the `Controller`, specify `hostname='0.0.0.0'` to listen on all available network interfaces, allowing connections from other machines or Docker containers. Also, verify the server is running and that no firewall is blocking the port.","cause":"This commonly happens when an `aiosmtpd` server is configured to listen only on localhost (e.g., '::1' or '127.0.0.1') by default, but a client attempts to connect from a different IP address, or when the server is not running or a firewall is blocking the connection.","error":"Connection refused"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"1.4.6","cli_name":"aiosmtpd","cli_version":"/usr/local/bin/aiosmtpd 1.4.6","type":"library","homepage":"https://aiosmtpd.readthedocs.io/","github":"https://github.com/aio-libs/aiosmtpd","docs":"https://aiosmtpd.readthedocs.io/","changelog":null,"pypi":"https://pypi.org/project/aiosmtpd/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["http-networking","communication"],"base_url":null,"auth_type":null,"install_checks":{"last_tested":"2026-05-22","tag":null,"tag_description":null,"installed_version":"1.4.6","pypi_latest":"1.4.6","is_stale":false,"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.23,"mem_mb":11.1,"disk_size":"19.4M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.6,"import_time_s":0.14,"mem_mb":11.1,"disk_size":"20M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.32,"mem_mb":12.4,"disk_size":"21.6M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.8,"import_time_s":0.28,"mem_mb":12.4,"disk_size":"22M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.53,"mem_mb":12.7,"disk_size":"13.4M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.6,"import_time_s":0.47,"mem_mb":12.7,"disk_size":"14M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.51,"mem_mb":13,"disk_size":"13.1M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.6,"import_time_s":0.46,"mem_mb":13,"disk_size":"14M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.19,"mem_mb":10.8,"disk_size":"18.9M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"aiosmtpd","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.9,"import_time_s":0.17,"mem_mb":10.8,"disk_size":"19M"}]},"_links":{"self":"https://checklist.day/api/registry/aiosmtpd","v1":"https://checklist.day/v1/registry/aiosmtpd","v1_install":"https://checklist.day/v1/registry/aiosmtpd/install","v1_imports":"https://checklist.day/v1/registry/aiosmtpd/imports","v1_compatibility":"https://checklist.day/v1/registry/aiosmtpd/compatibility","v1_quickstart":"https://checklist.day/v1/registry/aiosmtpd/quickstart","docs":"https://checklist.day/docs"}}