MailBlock Python SDK
Official Python SDK for the MailBlock email service. Send emails with confidence using a clean, Pythonic interface with comprehensive error handling, logging, and validation.
🚀 Features
- Fluent Builder Pattern - Intuitive, chainable API for email construction
- Comprehensive Error Handling - Detailed error messages with helpful suggestions
- Async/Await Support - Both synchronous and asynchronous email sending
- Email Scheduling - Schedule emails for future delivery
- Robust Validation - Client-side validation with detailed feedback
- Advanced Logging - Built-in debugging and request tracking
- Type Hints - Full type safety with mypy support
- Context Manager - Proper resource management
- Retry Mechanism - Automatic retry with exponential backoff
MailBlock Python SDK
Official Python SDK for the MailBlock email service. Send emails with confidence using a clean, Pythonic interface with comprehensive error handling, logging, and validation.
🚀 Features
- Fluent Builder Pattern - Intuitive, chainable API for email construction
- Comprehensive Error Handling - Detailed error messages with helpful suggestions
- Async/Await Support - Both synchronous and asynchronous email sending
- Email Scheduling - Schedule emails for future delivery
- Robust Validation - Client-side validation with detailed feedback
- Advanced Logging - Built-in debugging and request tracking
- Type Hints - Full type safety with mypy support
- Context Manager - Proper resource management
- Retry Mechanism - Automatic retry with exponential backoff
📦 Installation
# Install from PyPI
pip install mailblock
# For async support
pip install mailblock[async]
# For development
pip install mailblock[dev]
🔧 Quick Start
from mailblock import MailBlock
# Initialize client
client = MailBlock("your-api-key")
# Send a simple email
response = client.email() \
.to("recipient@example.com") \
.from_email("sender@example.com") \
.subject("Hello from MailBlock!") \
.text("This is a test email from the MailBlock Python SDK.") \
.send_sync()
if response.success:
print(f"Email sent! ID: {response.data['id']}")
else:
print(f"Error: {response.error}")
📚 Documentation
Client Initialization
from mailblock import MailBlock
# Basic initialization
client = MailBlock("your-api-key")
# With custom configuration
client = MailBlock(
api_key="your-api-key",
base_url="https://api.mailblock.com", # Custom API endpoint
timeout=30, # Request timeout in seconds
max_retries=3, # Maximum retry attempts
retry_delay=1.0, # Base retry delay in seconds
debug=True # Enable debug logging
)
Basic Email Sending
Synchronous
# Simple text email
response = client.email() \
.to("recipient@example.com") \
.from_email("sender@example.com") \
.subject("Hello World") \
.text("This is a plain text email.") \
.send_sync()
# HTML email with fallback text
response = client.email() \
.to("user@example.com") \
.from_email("noreply@yourapp.com") \
.subject("Welcome!") \
.text("Welcome to our service!") \
.html("<h1>Welcome!</h1><p>Thanks for joining us.</p>") \
.send_sync()
Asynchronous
import asyncio
async def send_email():
response = await client.email() \
.to("recipient@example.com") \
.from_email("sender@example.com") \
.subject("Async Email") \
.text("This email was sent asynchronously!") \
.send()
return response
# Run async function
response = asyncio.run(send_email())
Email Scheduling
from datetime import datetime, timedelta
# Schedule for 1 hour from now
send_time = datetime.now() + timedelta(hours=1)
response = client.email() \
.to("recipient@example.com") \
.from_email("scheduler@example.com") \
.subject("Scheduled Email") \
.text("This email was scheduled for delivery.") \
.schedule_at(send_time) \
.send_sync()
# Schedule with date string
response = client.email() \
.to("recipient@example.com") \
.from_email("scheduler@example.com") \
.subject("Scheduled Email") \
.text("Scheduled via date string.") \
.schedule_at("2024-12-25T10:00:00") \
.send_sync()
Error Handling
from mailblock import ValidationError, AuthenticationError, RateLimitError
try:
response = client.email() \
.to("invalid-email") \
.from_email("sender@example.com") \
.subject("Test") \
.text("Test content") \
.send_sync()
except ValidationError as e:
print(f"Validation error: {e}")
print(f"Suggestion: {e.suggestion}")
except AuthenticationError as e:
print(f"Authentication failed: {e}")
print(f"Request ID: {e.request_id}")
except RateLimitError as e:
print(f"Rate limited: {e}")
print(f"Suggestion: {e.suggestion}")
except Exception as e:
print(f"Unexpected error: {e}")
Advanced Usage
Bulk Email Sending
import asyncio
async def send_bulk_emails():
recipients = [
"user1@example.com",
"user2@example.com",
"user3@example.com"
]
# Send emails concurrently
tasks = []
for recipient in recipients:
task = client.email() \
.to(recipient) \
.from_email("bulk@example.com") \
.subject("Bulk Email") \
.text(f"Personal email for {recipient}") \
.send()
tasks.append(task)
responses = await asyncio.gather(*tasks, return_exceptions=True)
for i, response in enumerate(responses):
if isinstance(response, Exception):
print(f"Email {i+1} failed: {response}")
elif response.success:
print(f"Email {i+1} sent successfully")
else:
print(f"Email {i+1} failed: {response.error}")
asyncio.run(send_bulk_emails())
Custom Logger
import logging
# Set up custom logger
logger = logging.getLogger("my_app.mailblock")
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler("email.log")
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
# Use custom logger
client = MailBlock("your-api-key", debug=True, logger=logger)
Context Manager
# Ensures proper cleanup of resources
with MailBlock("your-api-key") as client:
response = client.email() \
.to("recipient@example.com") \
.from_email("sender@example.com") \
.subject("Context Manager Test") \
.text("This uses proper resource management.") \
.send_sync()
Direct Email Data
from mailblock import EmailData
# Create email data directly
email_data = EmailData(
to="recipient@example.com",
from_email="sender@example.com",
subject="Direct Send",
text="Sent without builder pattern",
html="<p>Sent <strong>without</strong> builder pattern</p>"
)
# Send directly
response = client.send_email_sync(email_data)
🔍 API Response
All send methods return an APIResponse object with the following structure:
class APIResponse:
success: bool # Whether the request succeeded
request_id: str # Unique request identifier
timestamp: datetime # When the request was made
duration: int # Request duration in milliseconds
# On success
data: Dict[str, Any] # Response data (includes email ID)
message: str # Success message
# On error
error: str # Error message
error_type: str # Error category
suggestion: str # Helpful suggestion
status_code: int # HTTP status code
endpoint: str # API endpoint used
Success Response Example
if response.success:
print(f"Email ID: {response.data['id']}")
print(f"Status: {response.data['status']}")
print(f"Duration: {response.duration}ms")
print(f"Request ID: {response.request_id}")
Error Response Example
if not response.success:
print(f"Error: {response.error}")
print(f"Type: {response.error_type}")
print(f"Suggestion: {response.suggestion}")
print(f"Status Code: {response.status_code}")
print(f"Request ID: {response.request_id}")
🛡️ Exception Hierarchy
MailBlockError # Base exception
├── ValidationError # Client-side validation errors
├── AuthenticationError # Invalid API key (401)
├── AuthorizationError # Insufficient permissions (403)
├── RateLimitError # Rate limiting (429)
├── ServerError # Server errors (5xx)
├── NetworkError # Connection issues
└── TimeoutError # Request timeouts
⚙️ Configuration Options
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
Required | Your MailBlock API key |
base_url |
str |
https://sdk-backend-production-20e1.up.railway.app |
API base URL |
timeout |
int |
30 |
Request timeout in seconds |
max_retries |
int |
3 |
Maximum retry attempts |
retry_delay |
float |
1.0 |
Base retry delay in seconds |
debug |
bool |
False |
Enable debug logging |
logger |
Logger |
None |
Custom logger instance |
🧪 Testing
# Install development dependencies
pip install -e .[dev]
# Run tests
pytest
# Run tests with coverage
pytest --cov=mailblock
# Run specific test file
pytest tests/test_client.py
# Run with verbose output
pytest -v
🏗️ Development
# Clone repository
git clone https://github.com/5ysc4ll/mailblock-python.git
cd mailblock-python
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install in development mode
pip install -e .[dev]
# Run linting
flake8 mailblock tests
black mailblock tests
isort mailblock tests
# Type checking
mypy mailblock
📋 Examples
Check out the examples/ directory for comprehensive usage examples:
basic_usage.py- Basic email sending patternsadvanced_usage.py- Advanced features and async usage
🤝 Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Run the test suite (
pytest) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🐛 Issues & Support
- Bug Reports: GitHub Issues
- Feature Requests: GitHub Issues
- Documentation: MailBlock Docs
- Support: support@mailblock.com
🔗 Links
- GitHub: https://github.com/5ysc4ll/python-sdk
- PyPI: https://pypi.org/project/mailblock/
- Documentation: https://docs.mailblock.com
- MailBlock Website: https://mailblock.com
📊 Changelog
v1.0.0 (Initial Release)
- ✨ Fluent builder pattern for email construction
- 🔄 Both sync and async email sending
- ⏰ Email scheduling support
- 🛡️ Comprehensive error handling and validation
- 📝 Advanced logging and debugging
- 🔁 Automatic retry with exponential backoff
- 📚 Complete type hints and mypy support
- ✅ Comprehensive test suite
- 📖 Full documentation and examples
🆕 Enhanced Features (v1.1.0)
Multiple Recipients & CC/BCC
Send emails to multiple recipients with carbon copy and blind carbon copy support:
# Multiple recipients with CC and BCC
response = client.email() \
.to(["user1@example.com", "user2@example.com"]) \
.cc("manager@example.com") \
.bcc(["archive@example.com", "backup@example.com"]) \
.from_email("sender@example.com") \
.subject("Team Update") \
.text("This email goes to multiple recipients") \
.send_sync()
Email Cancellation
Cancel scheduled emails before they are sent:
# Cancel a single email
response = client.cancel_email_sync("email_id_123")
if response.success:
print(f"Email cancelled: {response.data['current_status']}")
# Cancel multiple emails in bulk
email_ids = ["email_1", "email_2", "email_3"]
response = client.cancel_emails_sync(email_ids)
print(f"Cancelled {response.data['success_count']} emails")
Update Scheduled Emails
Modify scheduled emails before they are sent:
from mailblock import UpdateEmailData
from datetime import datetime, timedelta
# Create update data
updates = UpdateEmailData(
subject="Updated Subject",
body_text="Updated text content",
body_html="<h1>Updated HTML</h1>",
scheduled_at=datetime.now() + timedelta(hours=2) # Reschedule
)
# Update the email
response = client.update_scheduled_email_sync("email_id_123", updates)
if response.success:
print("Email updated successfully")
Async Support
All new methods support async operations:
import asyncio
async def manage_emails():
# Async email cancellation
response = await client.cancel_email("email_id_123")
# Async bulk cancellation
response = await client.cancel_emails(["email_1", "email_2"])
# Async email updates
updates = UpdateEmailData(subject="New Subject")
response = await client.update_scheduled_email("email_id_123", updates)
asyncio.run(manage_emails())
Enhanced Validation
Comprehensive validation for all email operations:
# Validates email formats in arrays
try:
client.email().to(["valid@example.com", "invalid-email"])
except ValidationError as e:
print(f"Validation failed: {e}")
# Validates email IDs
try:
client.cancel_emails_sync([]) # Empty array
except ValidationError as e:
print(f"Validation failed: {e}")
Built with ❤️ by the MailBlock Team
Metadata
Release files for mailblock 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| mailblock-1.1.0.tar.gz | 24.5 kB | Without provenance | Details for mailblock-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mailblock-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for mailblock-1.1.0-py3-none-any.whl |
Total release size: 46.1 kB
Release files / mailblock-1.1.0.tar.gz
| Download URL | mailblock-1.1.0.tar.gz |
|---|---|
| Size | 24.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
91f5cc713b28c1c23258f8b2ff9c88fafc3037d574a1018bc63fcd69ec4b8614
|
|
BLAKE2b-256 checksum How to use checksums |
b7c97daeb28ddcbdf349c47f634ed04af55e78c41adbd72f8f78fdef95a24f3d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.4
|
Release files / mailblock-1.1.0-py3-none-any.whl
| Download URL | mailblock-1.1.0-py3-none-any.whl |
|---|---|
| Size | 21.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b8903f392e8831f61c040f1a64f5472e9d45256a280920c7121560f76d4bdeef
|
|
BLAKE2b-256 checksum How to use checksums |
dcefb30b6422029b3ab7e04eaa487135720f2dd927dc1d3972c7dd2dca158228
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.4
|
Security for mailblock 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.