Overview of aiosmtplib
mainasyncio. It allows for non-blocking email transmission in asynchronous Python applications.repository·main·Indexed 19 days ago
https://github.com/cole/aiosmtplibAn asynchronous SMTP client for Python built for the asyncio framework. It serves as an async counterpart to the standard library's smtplib, supporting TLS/SSL, STARTTLS, and OAuth2 authentication (XOAUTH2) for providers like Gmail and Outlook. The library provides a high-level send function and a detailed SMTP class for managing connections, sending EmailMessage objects or raw strings, and integrating with SOCKS proxies via python-socks.
asyncio. It allows for non-blocking email transmission in asynchronous Python applications.asyncio framework. It serves as an asynchronous counterpart to the standard library's smtplib module and maintains a similar API, making it easy for developers familiar with smtplib to transition to asynchronous email sending.SMTP is a sequential protocol; commands must be sent in a specific order. Because of this, using asyncio.gather to run multiple SMTP.send_message tasks in parallel on a single client is not more efficient than running them in sequence, as the client must wait for one mail to finish before starting the next.
Best Practice: If you need to send a large volume of emails, create multiple SMTP instances (multiple connections) and distribute the workload across them.
Because OAuth2 access tokens are typically short-lived (e.g., 1 hour), your oauth_token_generator must be responsible for managing token lifecycle.
aiosmtplib does not track token expiry or automatically retry on authentication failure.
Your generator function must:
If you are using synchronous libraries like google-auth to handle refreshes, you should run the refresh logic in a separate thread using asyncio.to_thread to avoid blocking the event loop.
aiosmtplib supports three primary connection encryption modes. Choosing the correct one depends on the port and the security requirements of your SMTP server:
STARTTLS command after the initial greeting. Typically uses port 587. Most servers require this upgrade before allowing authentication (AUTH) commands.To send an email asynchronously, use the aiosmtplib.send() function. You can pass an EmailMessage object (from the standard email.message module) along with the hostname and port of your SMTP server. This function must be awaited within an asyncio event loop.
import asyncio
from email.message import EmailMessage
import aiosmtplib
message = EmailMessage()
message["From"] = "root@localhost"
message["To"] = "somebody@example.com"
message["Subject"] = "Hello World!"
message.set_content("Sent via aiosmtplib")
asyncio.run(aiosmtplib.send(message, hostname="127.0.0.1", port=25))By default, aiosmtplib will automatically upgrade the connection using STARTTLS if the server advertises support.
Important: Setting use_tls=True on a STARTTLS server will typically result in a connection error.
To opt out of automatic STARTTLS during the initial connection, set start_tls=False. You can then manually call SMTP.starttls() if required.
smtp_client = aiosmtplib.SMTP(
hostname="smtp.gmail.com",
port=587,
start_tls=False,
use_tls=False,
)
await smtp_client.connect()
await smtp_client.starttls()To use aiosmtplib, ensure your environment meets the following requirement:
aiosmtplib supports OAuth2 authentication via the XOAUTH2 mechanism, which is required by providers like Gmail and Outlook.com that have deprecated traditional password authentication.
To implement OAuth2, pass an asynchronous callable to the oauth_token_generator parameter. This callable must return a valid access token string.
Important Constraints:
oauth_token_generator parameter is mutually exclusive with the password parameter. You cannot provide both.XOAUTH2 authentication method.oauth_token_generator is called immediately before the XOAUTH2 command is sent to the server.import aiosmtplib
async def get_access_token() -> str:
# Your token refresh logic here
return "your_access_token"
await aiosmtplib.send(
message,
hostname="smtp.gmail.com",
port=465,
use_tls=True,
username="your.email@gmail.com",
oauth_token_generator=get_access_token,
)If the SMTP server supports direct connection via TLS/SSL (e.g., on port 465), pass use_tls=True to the send() function.
By default, aiosmtplib will automatically upgrade the connection using STARTTLS if the server advertises support.
start_tls=False.use_tls=True on a server that expects STARTTLS will typically result in a connection error.# Direct TLS/SSL
await send(message, hostname="smtp.gmail.com", port=465, use_tls=True)
# Opting out of STARTTLS
await send(message, hostname="smtp.gmail.com", port=587, start_tls=False)To authenticate with an SMTP server using standard credentials, pass the username and password keyword arguments to the send() coroutine.
await send(
message,
hostname="smtp.gmail.com",
port=587,
username="test@gmail.com",
password="test"
)The aiosmtplib.send() coroutine is the recommended entry point for most email sending use cases. To use it, create an email.message.EmailMessage object, set the required headers (at minimum From and one of To, Cc, or Bcc), and pass it to send() along with the SMTP server's hostname and port.
import asyncio
from email.message import EmailMessage
import aiosmtplib
async def send_hello_world():
message = EmailMessage()
message["From"] = "root@localhost"
message["To"] = "somebody@example.com"
message["Subject"] = "Hello World!"
message.set_content("Sent via aiosmtplib")
await aiosmtplib.send(message, hostname="127.0.0.1", port=1025)
asyncio.run(send_hello_world())