Skip to main content

Official Python SDK for MailBlock email service

Project description

MailBlock Python SDK

Python Version Version License

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

Python Version Version License

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:

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Run the test suite (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ› Issues & Support

๐Ÿ”— Links

๐Ÿ“Š 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mailblock-1.1.0.tar.gz (24.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mailblock-1.1.0-py3-none-any.whl (21.6 kB view details)

Uploaded Python 3

File details

Details for the file mailblock-1.1.0.tar.gz.

File metadata

  • Download URL: mailblock-1.1.0.tar.gz
  • Upload date:
  • Size: 24.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.4

File hashes

Hashes for mailblock-1.1.0.tar.gz
Algorithm Hash digest
SHA256 91f5cc713b28c1c23258f8b2ff9c88fafc3037d574a1018bc63fcd69ec4b8614
MD5 0d1fcf20c76f56fe07cb1c3e2dc4c05e
BLAKE2b-256 b7c97daeb28ddcbdf349c47f634ed04af55e78c41adbd72f8f78fdef95a24f3d

See more details on using hashes here.

File details

Details for the file mailblock-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: mailblock-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 21.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.4

File hashes

Hashes for mailblock-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b8903f392e8831f61c040f1a64f5472e9d45256a280920c7121560f76d4bdeef
MD5 c6000b9559faadf6756c702545cc2ec1
BLAKE2b-256 dcefb30b6422029b3ab7e04eaa487135720f2dd927dc1d3972c7dd2dca158228

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page