Python SDK
Python 3.10+
pip install
Send emails with Python using the official Laneful Python SDK. Built for modern Python applications with async support and comprehensive features.
Full Feature Support
Templates, attachments, tracking, webhooks
Async Support
Both sync and async operations
Modern Python
Python 3.10+ with type hints
On this page
Prerequisites
To get the most out of this guide, you'll need:
- • Python 3.10 or higher
- • pip package manager
- • A Laneful account with API key
- • Verified domain for sending emails
Installation
pip
Install the Laneful Python SDK using pip:
# Basic installation pip install laneful # With async support pip install laneful[async]
Quick Start
Send your first email in minutes:
Send Simple Text Email
from laneful import LanefulClient, Email, Address
# Initialize the client
client = LanefulClient(
base_url="https://your-endpoint.send.laneful.net",
auth_token="your-auth-token"
)
# Create an email
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="recipient@example.com", name="Recipient Name")],
subject="Hello from Laneful!",
text_content="This is a simple test email sent using the Laneful Python SDK.",
html_content="<h1>Hello from Laneful!</h1><p>This is a simple test email sent using the Laneful Python SDK.</p>"
)
# Send the email
try:
response = client.send_email(email)
print("✓ Email sent successfully!")
print(f"Response status: {response.status}")
except Exception as e:
print(f"✗ Error: {e}")Examples
Common use cases and patterns:
HTML Email with Tracking
from laneful import LanefulClient, Email, Address, TrackingSettings
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="recipient@example.com", name="Recipient Name")],
subject="HTML Email with Tracking",
html_content="<h1>Welcome!</h1><p>This is an <strong>HTML email</strong> with tracking enabled.</p>",
text_content="Welcome! This is an HTML email with tracking enabled.",
tag="welcome-email",
tracking=TrackingSettings(
opens=True,
clicks=True,
unsubscribes=True
)
)
response = client.send_email(email)Template Email
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="user@example.com", name="User")],
template_id="welcome-template",
template_data={
"name": "John Doe",
"company": "Acme Corporation",
"activation_link": "https://example.com/activate"
}
)
response = client.send_email(email)Email with Attachments
import base64
from laneful import LanefulClient, Email, Address, Attachment
# Create attachment from file
with open("/path/to/document.pdf", "rb") as f:
attachment_data = base64.b64encode(f.read()).decode()
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="user@example.com", name="User")],
subject="Document Attached",
text_content="Please find the document attached.",
attachments=[
Attachment(
file_name="document.pdf",
content=attachment_data,
content_type="application/pdf"
)
]
)
response = client.send_email(email)Multiple Recipients with Reply-To
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[
Address(email="user1@example.com", name="User One"),
Address(email="user2@example.com", name="User Two")
],
cc=[Address(email="cc@example.com", name="CC Recipient")],
bcc=[Address(email="bcc@example.com", name="BCC Recipient")],
reply_to=Address(email="reply@example.com", name="Reply To"),
subject="Email to Multiple Recipients",
text_content="This email is being sent to multiple recipients."
)
response = client.send_email(email)Scheduled Email
import time
# Schedule for 24 hours from now
send_time = int(time.time()) + (24 * 60 * 60)
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="user@example.com", name="User")],
subject="Scheduled Email",
text_content="This email was scheduled.",
send_time=send_time
)
response = client.send_email(email)Async Email Sending
import asyncio
from laneful import AsyncLanefulClient, Email, Address
async def send_async_email():
async with AsyncLanefulClient(
base_url="https://your-endpoint.send.laneful.net",
auth_token="your-auth-token"
) as client:
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="user@example.com", name="User")],
subject="Async Email",
text_content="This email was sent asynchronously.",
html_content="<h1>Async Email</h1><p>This email was sent asynchronously.</p>"
)
# Send email
try:
response = await client.send_email(email)
print("✓ Email sent successfully!")
print(f"Response status: {response.status}")
return response
except Exception as e:
print(f"✗ Error: {e}")
raise
# Run async function
asyncio.run(send_async_email())Batch Email Sending
emails = [
Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="user1@example.com", name="User One")],
subject="Email 1",
text_content="First email content."
),
Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="user2@example.com", name="User Two")],
subject="Email 2",
text_content="Second email content."
)
]
response = client.send_emails(emails)Context Manager Usage
# Sync context manager - automatic resource cleanup
with LanefulClient(
base_url="https://your-endpoint.send.laneful.net",
auth_token="your-auth-token"
) as client:
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="user@example.com", name="User")],
subject="Context Manager Email",
text_content="This email was sent using a context manager."
)
response = client.send_email(email)
print(f"Email sent: {response.status}")
# Client session automatically closed
# Async context manager
async with AsyncLanefulClient(
base_url="https://your-endpoint.send.laneful.net",
auth_token="your-auth-token"
) as client:
email = Email(
from_address=Address(email="sender@example.com", name="Your Name"),
to=[Address(email="user@example.com", name="User")],
subject="Async Context Manager Email",
text_content="This email was sent using an async context manager."
)
response = await client.send_email(email)
print(f"Email sent: {response.status}")
# Client session automatically closedWebhook Handler Example
from flask import Flask, request, jsonify
from laneful.webhooks import WebhookHandler, WebhookEvent
import json
app = Flask(__name__)
# Initialize webhook handler
webhook_handler = WebhookHandler(webhook_secret="your-webhook-secret")
# Register event handlers
@webhook_handler.on("email.delivered")
def handle_delivered(event: WebhookEvent):
print(f"Email {event.message_id} delivered to {event.email}")
@webhook_handler.on("email.opened")
def handle_opened(event: WebhookEvent):
print(f"Email {event.message_id} opened by {event.email}")
@webhook_handler.on("email.clicked")
def handle_clicked(event: WebhookEvent):
url = event.data.get("url")
print(f"Link clicked by {event.email}: {url}")
@webhook_handler.on("email.bounced")
def handle_bounced(event: WebhookEvent):
is_hard = event.data.get("is_hard")
print(f"Email bounced ({'hard' if is_hard else 'soft'}) for: {event.email}")
@app.route('/webhook', methods=['POST'])
def handle_webhook():
try:
# Get raw payload
payload = request.get_data(as_text=True)
# Extract signature from headers
signature = request.headers.get('x-webhook-signature')
if not signature:
return jsonify({'error': 'Missing signature'}), 401
# Verify signature and process webhook
if webhook_handler.verify_signature(payload, signature):
webhook_handler.process_webhook(payload)
return jsonify({'status': 'success'})
else:
return jsonify({'error': 'Invalid signature'}), 401
except Exception as e:
return jsonify({'error': str(e)}), 400
if __name__ == '__main__':
app.run(debug=True)API Reference
LanefulClient
Constructors
- •
LanefulClient(base_url: str, auth_token: str)- Initialize client with endpoint and auth token
Methods
- •
send_email(email: Email) → Response- Send single email - •
send_emails(emails: List[Email]) → Response- Send multiple emails
Required Fields
- •
from_address: Address- Sender address
Optional Fields
- •
to: List[Address]- Recipient addresses - •
cc: List[Address]- CC recipient addresses - •
bcc: List[Address]- BCC recipient addresses - •
reply_to: Address- Reply-to address - •
subject: str- Email subject - •
text_content: str- Plain text content - •
html_content: str- HTML content - •
template_id: str- Template ID - •
template_data: dict- Template data - •
attachments: List[dict]- File attachments - •
send_time: int- Scheduled send time (Unix timestamp) - •
tag: str- Email tag for categorization
Utility Classes
- •
Address(email: str, name: str = None)- Email address with optional name - •
Attachment(file_name: str, content: str, content_type: str)- Email attachment with base64 encoded content - •
TrackingSettings(opens: bool, clicks: bool, unsubscribes: bool)- Email tracking configuration - •
AsyncLanefulClient- Async version of the client for async/await operations
WebhookHandler
Initialization
- •
WebhookHandler(webhook_secret: str = None)- Initialize webhook handler with optional secret
Signature Verification
- •
verify_signature(payload: str, signature: str) → bool- Verifies webhook signature (supports sha256= prefix)
Event Handling
- •
on(event_type: str)- Decorator to register event handlers - •
register_handler(event_type: str, handler: Callable)- Register event handler function - •
process_webhook(payload: str)- Process webhook payload and call appropriate handlers
WebhookEvent
- •
event_type: str- Type of webhook event - •
message_id: str- Message ID of the email - •
email: str- Email address of the recipient - •
timestamp: int- Unix timestamp of the event - •
data: Dict[str, Any]- Additional event data
Error Handling
Comprehensive error handling with specific exception types:
from laneful.exceptions import LanefulError, LanefulAPIError, LanefulAuthError
try:
response = client.send_email(email)
print("✓ Email sent successfully!")
print(f"Response status: {response.status}")
except LanefulAuthError:
print("✗ Authentication failed - check your API token")
except LanefulAPIError as e:
print(f"✗ API error: {e.message} (status: {e.status_code})")
except LanefulError as e:
print(f"✗ Client error: {e.message}")
except Exception as e:
print(f"✗ Unexpected error: {e}")Error Handling
- •
LanefulAuthError- Authentication failures - •
LanefulAPIError- API request failures - •
LanefulError- General client errors - •
Exception- Unexpected errors
Best Practices
- • Always wrap API calls in try-except
- • Handle specific exception types first
- • Log errors with context information
- • Implement retry logic for transient failures
Webhook Handling
Comprehensive webhook handling with signature verification, payload parsing, and validation:
Basic Signature Verification
from laneful.webhooks import WebhookHandler
# Initialize webhook handler
webhook_handler = WebhookHandler(webhook_secret="your-webhook-secret")
# In your webhook handler
payload = request.get_data(as_text=True) # Get the raw request body
signature = request.headers.get('x-webhook-signature')
if webhook_handler.verify_signature(payload, signature):
# Process webhook data
webhook_handler.process_webhook(payload)
# Handle webhook events
else:
# Invalid signature
return jsonify({'error': 'Invalid signature'}), 401Advanced Webhook Processing
from laneful.webhooks import WebhookHandler, WebhookEvent
# Initialize webhook handler with event handlers
webhook_handler = WebhookHandler(webhook_secret="your-webhook-secret")
# Register event handlers
@webhook_handler.on("email.delivered")
def handle_delivery_event(event: WebhookEvent):
print(f"Email {event.message_id} delivered to {event.email}")
@webhook_handler.on("email.opened")
def handle_open_event(event: WebhookEvent):
print(f"Email {event.message_id} opened by {event.email}")
@webhook_handler.on("email.clicked")
def handle_click_event(event: WebhookEvent):
url = event.data.get("url")
print(f"Link clicked by {event.email}: {url}")
@webhook_handler.on("email.bounced")
def handle_bounce_event(event: WebhookEvent):
is_hard = event.data.get("is_hard")
print(f"Email bounced ({'hard' if is_hard else 'soft'}) for: {event.email}")
@webhook_handler.on("email.complained")
def handle_spam_complaint_event(event: WebhookEvent):
print(f"Spam complaint from {event.email}")
@webhook_handler.on("email.unsubscribed")
def handle_unsubscribe_event(event: WebhookEvent):
print(f"Unsubscribe from {event.email}")
# Complete webhook verification and processing workflow
try:
# Step 1: Get raw payload
payload = request.get_data(as_text=True)
# Step 2: Extract signature from headers
signature = request.headers.get('x-webhook-signature')
if not signature:
raise ValueError("Missing webhook signature")
# Step 3: Verify signature and process webhook
if webhook_handler.verify_signature(payload, signature):
webhook_handler.process_webhook(payload)
return jsonify({'status': 'success'})
else:
return jsonify({'error': 'Invalid signature'}), 401
except ValueError as e:
# Payload validation error
return jsonify({'error': str(e)}), 400
except Exception as e:
# Other errors
return jsonify({'error': str(e)}), 401Batch Mode Support
# The WebhookHandler automatically processes both single events and batches
# No need to check for batch mode - the handler manages this internally
# Single event payload
single_payload = '{"event_type": "email.delivered", "message_id": "123", ...}'
webhook_handler.process_webhook(single_payload)
# Batch event payload (multiple events in one webhook)
batch_payload = '{"events": [{"event_type": "email.delivered", ...}, {"event_type": "email.opened", ...}]}'
webhook_handler.process_webhook(batch_payload)
# All registered event handlers will be called for each event automaticallySupported Webhook Events
Delivery Events
- •
email.delivered- Email delivered successfully - •
email.bounced- Email bounced (hard or soft) - •
email.failed- Email failed to send - •
email.complained- Recipient marked email as spam
Engagement Events
- •
email.opened- Email opened by recipient - •
email.clicked- Link clicked in email - •
email.unsubscribed- Recipient unsubscribed
Webhook Features
Security
- • HMAC-SHA256 signature verification
- • Support for
sha256=prefix - • Constant-time comparison (timing attack protection)
- • Multiple header format support
Validation
- • JSON payload structure validation
- • Required field validation
- • Event type validation
- • Email format validation
- • UUID format validation for lane_id
Ready to Get Started?
Start sending emails with Python in minutes. Check out the examples and integrate with your application.