Asyncio SMTP client for sending emails asynchronously in Python applications
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
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.
"""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.
"""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: ...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())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())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())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())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())SMTPConnectError: General connection failuresSMTPConnectTimeoutError: Connection timeoutsSMTPServerDisconnected: Unexpected disconnectionsSMTPConnectResponseError: Invalid server greetingSMTPAuthenticationError: Authentication failuresSMTPNotSupported: Unsupported features/commandsSMTPSenderRefused: Sender address rejectedSMTPRecipientRefused: Recipient address rejectedSMTPRecipientsRefused: Multiple recipients rejectedSMTPDataError: Message content rejectedSMTPTimeoutError: General operation timeoutsSMTPReadTimeoutError: Server response timeoutsSMTPHeloError: HELO/EHLO command failuresSMTPResponseException: General server response errorsSMTPException: Base class for all SMTP-related errorsInstall with Tessl CLI
npx tessl i tessl/pypi-aiosmtplib