aiosmtplib Documentation

repository·main·Indexed 19 days ago

https://github.com/cole/aiosmtplib

An 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.

Tokens
15.3K
Snippets
50
Records
67
Agent score
65%

What's inside aiosmtplib

  1. Introduction to aiosmtplib

    main
    aiosmtplib is an asynchronous SMTP client designed for use with Python's 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.
  2. Optimizing high-volume email sending

    main

    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.

  3. Handle OAuth2 token expiry and refresh

    main

    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:

    1. Check if the current token is expired.
    2. Refresh the token if necessary.
    3. Return a valid, non-expired token.

    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.

  4. Understand SMTP encryption types in aiosmtplib

    main

    aiosmtplib supports three primary connection encryption modes. Choosing the correct one depends on the port and the security requirements of your SMTP server:

    1. Plaintext: The connection is entirely unencrypted. Typically uses port 25. Note that most authentication methods are unsupported on unencrypted connections. This is best for local servers or testing.
    2. TLS/SSL: The TLS handshake occurs immediately upon connection establishment, ensuring all traffic is encrypted from the start. Typically uses port 465. This is the recommended method where available.
    3. STARTTLS: An initial unencrypted connection is established, and the connection is upgraded to an encrypted state via the STARTTLS command after the initial greeting. Typically uses port 587. Most servers require this upgrade before allowing authentication (AUTH) commands.
  5. Quickstart with aiosmtplib

    main

    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))
  6. Handle STARTTLS connections

    main

    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()
  7. Use OAuth2 authentication (XOAUTH2) with aiosmtplib

    main

    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:

    • The oauth_token_generator parameter is mutually exclusive with the password parameter. You cannot provide both.
    • The SMTP server must support the XOAUTH2 authentication method.
    • The 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,
    )
  8. Connect using TLS/SSL or STARTTLS

    main

    Direct TLS/SSL

    If the SMTP server supports direct connection via TLS/SSL (e.g., on port 465), pass use_tls=True to the send() function.

    STARTTLS

    By default, aiosmtplib will automatically upgrade the connection using STARTTLS if the server advertises support.

    • To opt out of automatic STARTTLS on connect, pass start_tls=False.
    • Note: Setting 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)
  9. Authenticate with username and password

    main

    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"
    )
  10. Send an email using the send() coroutine

    main

    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())