Official Python SDK for the MailBlock email service. Send emails with confidence using a clean, Pythonic interface with comprehensive error handling, logging, and validation.
- 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
Official Python SDK for the MailBlock email service. Send emails with confidence using a clean, Pythonic interface with comprehensive error handling, logging, and validation.
- 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
# Install from PyPI
pip install mailblock
# For async support
pip install mailblock[async]
# For development
pip install mailblock[dev]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}")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
)# 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()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())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()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}")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())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)# 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()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)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 usedif 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}")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}")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| 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 | 
# 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# Clone repository
git clone https://github.com/5ysc4ll/python-sdk.git
cd python-sdk
# 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 mailblockCheck out the examples/ directory for comprehensive usage examples:
- basic_usage.py- Basic email sending patterns
- advanced_usage.py- Advanced features and async usage
- 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
This project is licensed under the MIT License - see the LICENSE file for details.
- Bug Reports: GitHub Issues
- Feature Requests: GitHub Issues
- Documentation: MailBlock Docs
- Support: support@mailblock.com
- GitHub: https://github.com/5ysc4ll/python-sdk
- PyPI: https://pypi.org/project/mailblock/
- Documentation: https://docs.mailblock.com
- MailBlock Website: https://mailblock.com
- β¨ 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
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()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")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")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())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