Mailgun adapter
mailgun_adapter
¶
Mailgun adapter for the communication abstraction
MailgunAdapter(config: Any = None)
¶
Mailgun email client adapter
This class wraps the existing Mailgun functionality to provide a consistent interface with other email providers.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
config | Any | Configuration object (if None, will use get_cfg()) | None |
Source code in src/pytanis/communication/mailgun_adapter.py
def __init__(self, config: Any = None):
"""Initialize the Mailgun adapter
Args:
config: Configuration object (if None, will use get_cfg())
"""
# Lazy import to avoid dependency issues
try:
from pytanis.config import get_cfg
from pytanis.mailgun.mail import MailClient
except ImportError as e:
msg = 'Mailgun dependencies not installed. Install with: pip install pytanis[mailgun]'
raise ImportError(msg) from e
if config is None:
config = get_cfg()
self._client = MailClient(config=config)
self._config = config
send_bulk_emails(messages: list[EmailMessage], rate_limit: int | None = None) -> list[str | None]
¶
Send multiple email messages
Note: This implementation sends emails individually as the Mailgun client handles batching internally based on its batch_size configuration.
Source code in src/pytanis/communication/mailgun_adapter.py
def send_bulk_emails(self, messages: list[EmailMessage], rate_limit: int | None = None) -> list[str | None]:
"""Send multiple email messages
Note: This implementation sends emails individually as the Mailgun client
handles batching internally based on its batch_size configuration.
"""
results = []
# If rate limit is specified, override the client's wait time
if rate_limit:
original_batch_size = self._client.batch_size
original_wait_time = self._client.wait_time
self._client.batch_size = 1 # Send one at a time
self._client.wait_time = int(1.0 / rate_limit)
try:
for i, message in enumerate(messages):
try:
# For bulk sends, we could optimize by creating a single Mail object
# with all recipients if all messages have the same subject/body
msg_id = self.send_email(message)
results.append(msg_id)
except Exception as e:
_logger.error('Failed to send email', error=str(e), index=i, to=message.to)
results.append(None)
finally:
# Restore original settings if we modified them
if rate_limit:
self._client.batch_size = original_batch_size
self._client.wait_time = original_wait_time
return results
send_email(message: EmailMessage) -> str | None
¶
Send an email message using Mailgun
Source code in src/pytanis/communication/mailgun_adapter.py
def send_email(self, message: EmailMessage) -> str | None:
"""Send an email message using Mailgun"""
try:
# Convert to Mailgun format
from pytanis.mailgun.mail import Mail, Recipient
# Extract recipients
if not message.to:
msg = 'No recipients specified'
raise ValueError(msg)
# Create recipient objects for all recipients
recipients = []
for email in message.to:
# Extract name from email if no metadata is provided
name = email.split('@')[0]
recipients.append(
Recipient(
name=name,
email=email,
)
)
# Create mail object with correct parameters
mail = Mail(
subject=message.subject,
body=message.body,
recipients=recipients,
)
# Send email using the correct method name
responses, errors = self._client.send(mail)
# Check for errors
if errors:
error_msgs = [f'{recipient.email}: {error!s}' for recipient, error in errors]
_logger.error('Errors sending emails', errors=error_msgs)
if not responses:
msg = f'All emails failed: {"; ".join(error_msgs)}'
raise OSError(msg)
# Handle additional recipients as CC/BCC (not supported by current Mailgun implementation)
if message.cc or message.bcc:
_logger.warning(
'Mailgun adapter currently does not support CC/BCC recipients.',
cc=message.cc,
bcc=message.bcc,
)
# Return the first response ID if available
if responses and hasattr(responses[0], 'json'):
return responses[0].json().get('id')
return None
except Exception as e:
msg = f'Error sending email via Mailgun: {e}'
raise OSError(msg) from e