Send Email with Python
Learn how to send your first email with the Transactional Python SDK. Includes sync and async examples.
Beginner
email
getting-started
sdk
python
Prerequisites
- Python 3.8+ installed
- pip package manager
- Transactional account with API key
- Verified sending domain
CODE
Full Example
import os
from transactional import Transactional
# Initialize the client
client = Transactional(api_key=os.environ['TRANSACTIONAL_API_KEY'])
def send_welcome_email(to_email: str, user_name: str) -> dict:
"""Send a welcome email to a new user."""
result = client.emails.send(
from_email='hello@yourdomain.com',
to=to_email,
subject=f'Welcome, {user_name}!',
html=f'''
<h1>Welcome to Our Platform!</h1>
<p>Hi {user_name},</p>
<p>Thanks for signing up. We're excited to have you on board.</p>
<a href="https://app.example.com/get-started">Get Started</a>
''',
text=f'''
Welcome to Our Platform!
Hi {user_name},
Thanks for signing up. We're excited to have you on board.
Get started: https://app.example.com/get-started
''',
)
if result.error:
print(f'Error: {result.error.code} - {result.error.message}')
return {'success': False, 'error': result.error.message}
print(f'Email sent! ID: {result.data.id}')
return {'success': True, 'id': result.data.id}
# Example usage
if __name__ == '__main__':
response = send_welcome_email(
to_email='user@example.com',
user_name='Alice'
)
print(response)
Understanding the Code
Client Initialization
from transactional import Transactional
client = Transactional(api_key=os.environ['TRANSACTIONAL_API_KEY'])Always use environment variables for your API key. Never hardcode credentials in your source code.
Send Options
The send method accepts these parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
from_email | str | Yes | Sender email address |
to | str | list[str] | Yes | Recipient(s) |
subject | str | Yes | Email subject line |
html | str | No | HTML content |
text | str | No | Plain text content |
cc | str | list[str] | No | CC recipients |
bcc | str | list[str] | No | BCC recipients |
reply_to | str | No | Reply-to address |
attachments | list[dict] | No | File attachments |
metadata | dict | No | Custom metadata for tracking |
tags | list[str] | No | Tags for categorization |
Result Pattern
The SDK uses a result pattern instead of exceptions:
result = client.emails.send(...)
if result.error:
# Handle the error
print(f'{result.error.code}: {result.error.message}')
else:
# Use the data
print(f'Sent: {result.data.id}')
print(f'Status: {result.data.status}')Error Handling
Common Error Codes
| Code | Description | How to Handle |
|---|---|---|
INVALID_API_KEY | API key is invalid or missing | Check your API key |
INVALID_EMAIL | Email address format is invalid | Validate email before sending |
DOMAIN_NOT_VERIFIED | Sending domain not verified | Verify domain in dashboard |
RATE_LIMITED | Too many requests | Implement exponential backoff |
QUOTA_EXCEEDED | Monthly quota exceeded | Upgrade plan or wait for reset |
Robust Error Handling Example
def send_email_safely(to: str, subject: str, html: str) -> dict:
"""Send email with comprehensive error handling."""
try:
result = client.emails.send(
from_email='hello@yourdomain.com',
to=to,
subject=subject,
html=html,
)
if result.error:
match result.error.code:
case 'INVALID_EMAIL':
return {'success': False, 'error': 'Invalid email address', 'retry': False}
case 'RATE_LIMITED':
return {'success': False, 'error': 'Rate limited', 'retry': True}
case 'QUOTA_EXCEEDED':
return {'success': False, 'error': 'Quota exceeded', 'retry': False}
case _:
return {'success': False, 'error': result.error.message, 'retry': True}
return {'success': True, 'id': result.data.id}
except Exception as e:
# Network errors, timeouts, etc.
return {'success': False, 'error': str(e), 'retry': True}Best Practices
1. Always Include Plain Text
Some users prefer plain text emails, and having a text version improves deliverability:
result = client.emails.send(
from_email='hello@yourdomain.com',
to=to_email,
subject=subject,
html='<h1>Hello World</h1>',
text='Hello World', # Always include this
)2. Use Metadata for Tracking
Add metadata to correlate emails with your application data:
result = client.emails.send(
from_email='orders@yourdomain.com',
to=customer.email,
subject='Order Shipped',
html=html_content,
metadata={
'order_id': order.id,
'customer_id': customer.id,
'email_type': 'shipping_notification',
},
)3. Validate Before Sending
Catch invalid emails before they waste API calls:
from transactional import Transactional
client = Transactional(api_key=os.environ['TRANSACTIONAL_API_KEY'])
# Validate first
validation = client.emails.validate(email=user_input)
if not validation.data.valid:
print(f'Invalid email: {validation.data.reason}')
return
# Then send
result = client.emails.send(...)