CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-aiosmtplib

Asyncio SMTP client for sending emails asynchronously in Python applications

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

exceptions.mddocs/

Exception Handling

aiosmtplib provides a comprehensive exception hierarchy for handling different types of SMTP errors. These exceptions allow applications to handle specific error conditions appropriately and provide meaningful error messages to users.

Capabilities

Exception Hierarchy

The exception hierarchy is designed to allow both specific and general error handling.

class SMTPException(Exception):
    """
    Base class for all SMTP exceptions.
    
    Attributes:
    - message: str - Error message
    """
    def __init__(self, message: str, /) -> None: ...

class SMTPServerDisconnected(SMTPException, ConnectionError):
    """
    The connection was lost unexpectedly, or a command was run that requires
    a connection.
    """

class SMTPConnectError(SMTPException, ConnectionError):
    """
    An error occurred while connecting to the SMTP server.
    """

class SMTPTimeoutError(SMTPException, TimeoutError):
    """
    A timeout occurred while performing a network operation.
    """

class SMTPConnectTimeoutError(SMTPTimeoutError, SMTPConnectError):
    """
    A timeout occurred while connecting to the SMTP server.
    """

class SMTPReadTimeoutError(SMTPTimeoutError):
    """
    A timeout occurred while waiting for a response from the SMTP server.
    """

class SMTPNotSupported(SMTPException):
    """
    A command or argument sent to the SMTP server is not supported.
    """

Server Response Exceptions

Exceptions that correspond to specific SMTP server response codes.

class SMTPResponseException(SMTPException):
    """
    Base class for all server responses with error codes.
    
    Attributes:
    - code: int - SMTP response code
    - message: str - SMTP response message
    """
    def __init__(self, code: int, message: str, /) -> None: ...

class SMTPConnectResponseError(SMTPResponseException, SMTPConnectError):
    """
    The SMTP server returned an invalid response code after connecting.
    """

class SMTPHeloError(SMTPResponseException):
    """
    Server refused HELO or EHLO.
    """

class SMTPDataError(SMTPResponseException):
    """
    Server refused DATA content.
    """

class SMTPAuthenticationError(SMTPResponseException):
    """
    Server refused our AUTH request; may be caused by invalid credentials.
    """

Recipient and Sender Exceptions

Specific exceptions for email address-related errors.

class SMTPSenderRefused(SMTPResponseException):
    """
    SMTP server refused the message sender.
    
    Attributes:
    - code: int - SMTP response code
    - message: str - SMTP response message  
    - sender: str - The refused sender address
    """
    def __init__(self, code: int, message: str, sender: str, /) -> None: ...

class SMTPRecipientRefused(SMTPResponseException):
    """
    SMTP server refused a message recipient.
    
    Attributes:
    - code: int - SMTP response code
    - message: str - SMTP response message
    - recipient: str - The refused recipient address
    """
    def __init__(self, code: int, message: str, recipient: str, /) -> None: ...

class SMTPRecipientsRefused(SMTPException):
    """
    SMTP server refused multiple recipients.
    
    Attributes:
    - recipients: list[SMTPRecipientRefused] - List of refused recipient errors
    """
    def __init__(self, recipients: list[SMTPRecipientRefused], /) -> None: ...

Usage Examples

Basic Exception Handling

import asyncio
import aiosmtplib
from email.message import EmailMessage

async def basic_error_handling():
    message = EmailMessage()
    message["From"] = "sender@example.com"
    message["To"] = "recipient@example.com"
    message["Subject"] = "Test Email"
    message.set_content("Test message")
    
    try:
        response = await aiosmtplib.send(
            message,
            hostname="smtp.example.com",
            port=587,
            start_tls=True,
            username="user@example.com",
            password="password"
        )
        print(f"Email sent successfully: {response}")
        
    except aiosmtplib.SMTPException as e:
        print(f"SMTP error occurred: {e}")

asyncio.run(basic_error_handling())

Specific Exception Handling

import asyncio
import aiosmtplib
from email.message import EmailMessage

async def specific_error_handling():
    message = EmailMessage()
    message["From"] = "sender@example.com"
    message["To"] = "invalid@nonexistent.domain"
    message["Subject"] = "Test Email"
    message.set_content("Test message")
    
    try:
        response = await aiosmtplib.send(
            message,
            hostname="smtp.example.com",
            port=587,
            start_tls=True,
            username="user@example.com",
            password="wrong-password",
            timeout=10
        )
        print(f"Email sent: {response}")
        
    except aiosmtplib.SMTPConnectTimeoutError as e:
        print(f"Connection timed out: {e}")
        # Maybe retry with longer timeout
        
    except aiosmtplib.SMTPConnectError as e:
        print(f"Failed to connect to server: {e}")
        # Maybe try alternative server
        
    except aiosmtplib.SMTPAuthenticationError as e:
        print(f"Authentication failed (code {e.code}): {e.message}")
        # Prompt user for correct credentials
        
    except aiosmtplib.SMTPSenderRefused as e:
        print(f"Sender '{e.sender}' refused (code {e.code}): {e.message}")
        # Use different sender address
        
    except aiosmtplib.SMTPRecipientRefused as e:
        print(f"Recipient '{e.recipient}' refused (code {e.code}): {e.message}")
        # Remove invalid recipient
        
    except aiosmtplib.SMTPRecipientsRefused as e:
        print("Multiple recipients refused:")
        for recipient_error in e.recipients:
            print(f"  {recipient_error.recipient}: {recipient_error.message}")
        # Handle each refused recipient
        
    except aiosmtplib.SMTPDataError as e:
        print(f"Message content refused (code {e.code}): {e.message}")
        # Modify message content
        
    except aiosmtplib.SMTPReadTimeoutError as e:
        print(f"Server response timed out: {e}")
        # Maybe retry operation
        
    except aiosmtplib.SMTPNotSupported as e:
        print(f"Operation not supported: {e}")
        # Use alternative approach
        
    except aiosmtplib.SMTPServerDisconnected as e:
        print(f"Server disconnected unexpectedly: {e}")
        # Reconnect and retry
        
    except aiosmtplib.SMTPTimeoutError as e:
        print(f"General timeout error: {e}")
        # Increase timeout and retry
        
    except aiosmtplib.SMTPResponseException as e:
        print(f"Server error (code {e.code}): {e.message}")
        # Handle other server response errors
        
    except aiosmtplib.SMTPException as e:
        print(f"General SMTP error: {e}")
        # Handle any other SMTP-related errors

asyncio.run(specific_error_handling())

Client Error Handling

import asyncio
import aiosmtplib

async def client_error_handling():
    smtp = aiosmtplib.SMTP(hostname="smtp.example.com", port=587)
    
    try:
        # Connection errors
        await smtp.connect()
        
    except aiosmtplib.SMTPConnectTimeoutError as e:
        print(f"Connection timed out: {e}")
        return
    except aiosmtplib.SMTPConnectError as e:
        print(f"Connection failed: {e}")
        return
    
    try:
        # Authentication errors
        await smtp.login("user", "password")
        
    except aiosmtplib.SMTPAuthenticationError as e:
        print(f"Authentication failed: {e.code} {e.message}")
        smtp.close()
        return
    except aiosmtplib.SMTPNotSupported as e:
        print(f"Authentication not supported: {e}")
        # Continue without authentication
    
    try:
        # Sending errors
        response = await smtp.sendmail(
            "sender@example.com",
            ["recipient1@example.com", "invalid@bad.domain"],
            "Subject: Test\n\nTest message"
        )
        
        # Check individual recipient responses
        for recipient, smtp_response in response[0].items():
            print(f"{recipient}: {smtp_response}")
            
    except aiosmtplib.SMTPSenderRefused as e:
        print(f"Sender refused: {e.sender} - {e.message}")
    except aiosmtplib.SMTPRecipientsRefused as e:
        print("Some recipients refused:")
        for error in e.recipients:
            print(f"  {error.recipient}: {error.message}")
    except aiosmtplib.SMTPDataError as e:
        print(f"Message data refused: {e.message}")
    except aiosmtplib.SMTPServerDisconnected as e:
        print(f"Connection lost during operation: {e}")
    
    finally:
        if smtp.is_connected:
            try:
                await smtp.quit()
            except aiosmtplib.SMTPException:
                # Force close if quit fails
                smtp.close()

asyncio.run(client_error_handling())

Error Recovery Strategies

import asyncio
import aiosmtplib
from email.message import EmailMessage

async def error_recovery_example():
    message = EmailMessage()
    message["From"] = "sender@example.com"
    message["To"] = "recipient@example.com"
    message["Subject"] = "Test with Recovery"
    message.set_content("Test message with error recovery")
    
    # List of backup servers
    smtp_servers = [
        {"hostname": "smtp.primary.com", "port": 587},
        {"hostname": "smtp.backup.com", "port": 587},
        {"hostname": "smtp.fallback.com", "port": 25},
    ]
    
    for server_config in smtp_servers:
        try:
            response = await aiosmtplib.send(
                message,
                hostname=server_config["hostname"],
                port=server_config["port"],
                start_tls=True,
                username="user@example.com",
                password="password",
                timeout=30
            )
            print(f"Email sent via {server_config['hostname']}: {response}")
            break  # Success, exit loop
            
        except aiosmtplib.SMTPConnectError as e:
            print(f"Failed to connect to {server_config['hostname']}: {e}")
            continue  # Try next server
            
        except aiosmtplib.SMTPTimeoutError as e:
            print(f"Timeout with {server_config['hostname']}: {e}")
            continue  # Try next server
            
        except aiosmtplib.SMTPAuthenticationError as e:
            print(f"Auth failed with {server_config['hostname']}: {e}")
            # Authentication issue - don't retry with other servers
            break
            
        except aiosmtplib.SMTPException as e:
            print(f"SMTP error with {server_config['hostname']}: {e}")
            continue  # Try next server
    else:
        print("Failed to send email with all configured servers")

asyncio.run(error_recovery_example())

Exception Information Access

import asyncio
import aiosmtplib

async def exception_info_example():
    smtp = aiosmtplib.SMTP(hostname="smtp.example.com", port=587)
    
    try:
        await smtp.connect()
        await smtp.sendmail(
            "invalid-sender",  # Invalid sender format
            ["recipient@example.com"],
            "Subject: Test\n\nTest message"
        )
        
    except aiosmtplib.SMTPSenderRefused as e:
        print("Sender refused details:")
        print(f"  Response code: {e.code}")
        print(f"  Server message: {e.message}")
        print(f"  Refused sender: {e.sender}")
        print(f"  Exception args: {e.args}")
        
    except aiosmtplib.SMTPRecipientRefused as e:
        print("Recipient refused details:")
        print(f"  Response code: {e.code}")
        print(f"  Server message: {e.message}")
        print(f"  Refused recipient: {e.recipient}")
        
    except aiosmtplib.SMTPResponseException as e:
        print("Server response error:")
        print(f"  Response code: {e.code}")
        print(f"  Server message: {e.message}")
        
    except aiosmtplib.SMTPException as e:
        print("General SMTP error:")
        print(f"  Error message: {e.message}")
        print(f"  Exception type: {type(e).__name__}")
    
    finally:
        smtp.close()

asyncio.run(exception_info_example())

Exception Categories

Connection Exceptions

  • SMTPConnectError: General connection failures
  • SMTPConnectTimeoutError: Connection timeouts
  • SMTPServerDisconnected: Unexpected disconnections
  • SMTPConnectResponseError: Invalid server greeting

Authentication Exceptions

  • SMTPAuthenticationError: Authentication failures
  • SMTPNotSupported: Unsupported features/commands

Message Exceptions

  • SMTPSenderRefused: Sender address rejected
  • SMTPRecipientRefused: Recipient address rejected
  • SMTPRecipientsRefused: Multiple recipients rejected
  • SMTPDataError: Message content rejected

Operation Exceptions

  • SMTPTimeoutError: General operation timeouts
  • SMTPReadTimeoutError: Server response timeouts
  • SMTPHeloError: HELO/EHLO command failures
  • SMTPResponseException: General server response errors

General Exception

  • SMTPException: Base class for all SMTP-related errors

Install with Tessl CLI

npx tessl i tessl/pypi-aiosmtplib

docs

exceptions.md

high-level-api.md

index.md

smtp-client.md

utilities.md

tile.json