Skip to main content

Mailnow Python SDK

A simple, type-safe Python SDK for the Mailnow email API. Send emails programmatically with just a few lines of code.

Python Version Type Checked License: MIT

Features

  • 🚀 Simple, intuitive API
  • 🔒 Type-safe with full type hints
  • ✅ Comprehensive input validation
  • 🎯 Detailed error handling
  • 📝 Extensive documentation
  • 🧪 Thoroughly tested

Installation

Install the SDK using pip:

pip install py-mailnow

Quick Start

from mailnow import MailnowClient

# Initialize the client with your API key
client = MailnowClient(api_key="mn_live_7e59df7ce4a14545b443837804ec9722")

# Send an email
response = client.send_email(
    from_email="sender@example.com",
    to_email="recipient@example.com",
    subject="Hello from Mailnow!",
    html="<h1>Welcome!</h1><p>This is your first email.</p>"
)

print(f"Email sent! Message ID: {response['message_id']}")

API Key Format

Your Mailnow API key must be in one of the following formats:

  • Production: mn_live_ followed by your unique key (e.g., mn_live_7e59df7ce4a14545b443837804ec9722)
  • Testing: mn_test_ followed by your unique key (e.g., mn_test_abc123def456)

You can find your API key in your Mailnow dashboard.

Usage Examples

Basic Email Sending

from mailnow import MailnowClient

client = MailnowClient(api_key="mn_live_7e59df7ce4a14545b443837804ec9722")

response = client.send_email(
    from_email="noreply@yourcompany.com",
    to_email="customer@example.com",
    subject="Welcome to Our Service",
    html="<h1>Welcome!</h1><p>Thanks for signing up.</p>"
)

print(response)
# Output: {'success': True, 'message_id': 'msg_abc123', 'status': 'queued'}

With Error Handling

from mailnow import (
    MailnowClient,
    MailnowError,
    MailnowValidationError,
    MailnowAuthError,
    MailnowRateLimitError,
    MailnowServerError,
    MailnowConnectionError
)

client = MailnowClient(api_key="mn_live_7e59df7ce4a14545b443837804ec9722")

try:
    response = client.send_email(
        from_email="sender@example.com",
        to_email="recipient@example.com",
        subject="Important Update",
        html="<p>Your account has been updated.</p>"
    )
    print(f"✓ Email sent successfully: {response['message_id']}")
    
except MailnowValidationError as e:
    print(f"✗ Validation error: {e}")
    # Handle invalid input (missing fields, invalid email format, etc.)
    
except MailnowAuthError as e:
    print(f"✗ Authentication error: {e}")
    # Handle invalid or expired API key
    
except MailnowRateLimitError as e:
    print(f"✗ Rate limit exceeded: {e}")
    # Implement exponential backoff or retry logic
    
except MailnowServerError as e:
    print(f"✗ Server error: {e}")
    # Retry the request after a delay
    
except MailnowConnectionError as e:
    print(f"✗ Connection error: {e}")
    # Check network connectivity
    
except MailnowError as e:
    print(f"✗ Unexpected error: {e}")
    # Catch any other SDK errors

Sending HTML Emails

from mailnow import MailnowClient

client = MailnowClient(api_key="mn_live_7e59df7ce4a14545b443837804ec9722")

html_content = """
<!DOCTYPE html>
<html>
<head>
    <style>
        body { font-family: Arial, sans-serif; }
        .header { background-color: #4CAF50; color: white; padding: 20px; }
        .content { padding: 20px; }
    </style>
</head>
<body>
    <div class="header">
        <h1>Welcome to Our Newsletter</h1>
    </div>
    <div class="content">
        <p>Hello,</p>
        <p>Thank you for subscribing to our newsletter!</p>
        <p>Best regards,<br>The Team</p>
    </div>
</body>
</html>
"""

response = client.send_email(
    from_email="newsletter@yourcompany.com",
    to_email="subscriber@example.com",
    subject="Welcome to Our Newsletter",
    html=html_content
)

Handling Multiple Recipients

from mailnow import MailnowClient, MailnowError

client = MailnowClient(api_key="mn_live_7e59df7ce4a14545b443837804ec9722")

recipients = [
    "user1@example.com",
    "user2@example.com",
    "user3@example.com"
]

for recipient in recipients:
    try:
        response = client.send_email(
            from_email="notifications@yourcompany.com",
            to_email=recipient,
            subject="System Notification",
            html="<p>This is an automated notification.</p>"
        )
        print(f"✓ Sent to {recipient}: {response['message_id']}")
    except MailnowError as e:
        print(f"✗ Failed to send to {recipient}: {e}")
        continue

Exception Types

The SDK provides detailed exception types for different error scenarios:

MailnowError

Base exception for all Mailnow SDK errors. Catch this to handle any SDK-related error.

try:
    client.send_email(...)
except MailnowError as e:
    print(f"SDK error: {e}")

MailnowValidationError

Raised when input validation fails. This includes:

  • Missing or empty required parameters (from_email, to_email, subject, html)
  • Invalid email address format
  • Invalid API key format
  • API returns 400 Bad Request
try:
    client.send_email(
        from_email="invalid-email",  # Invalid format
        to_email="user@example.com",
        subject="Test",
        html="<p>Test</p>"
    )
except MailnowValidationError as e:
    print(f"Validation error: {e}")

MailnowAuthError

Raised when authentication fails. This includes:

  • Missing or None API key
  • Empty API key
  • Invalid API key format (doesn't start with mn_live_ or mn_test_)
  • API returns 401 Unauthorized
try:
    client = MailnowClient(api_key="invalid_key")
except MailnowAuthError as e:
    print(f"Authentication error: {e}")

MailnowRateLimitError

Raised when rate limit is exceeded (API returns 429 Too Many Requests). Consider implementing exponential backoff retry logic.

import time

try:
    client.send_email(...)
except MailnowRateLimitError as e:
    print(f"Rate limit exceeded: {e}")
    time.sleep(60)  # Wait before retrying

MailnowServerError

Raised when the Mailnow API experiences an internal error (5xx status codes). Consider retrying the request after a delay.

import time

max_retries = 3
for attempt in range(max_retries):
    try:
        response = client.send_email(...)
        break
    except MailnowServerError as e:
        if attempt < max_retries - 1:
            time.sleep(2 ** attempt)  # Exponential backoff
            continue
        raise

MailnowConnectionError

Raised when network connection fails. This includes:

  • Network connection cannot be established
  • Request times out
  • DNS resolution fails
  • Any other network-level error
try:
    client.send_email(...)
except MailnowConnectionError as e:
    print(f"Connection error: {e}")
    # Check network connectivity or retry

Type Hints and mypy Compatibility

The Mailnow SDK is fully type-annotated and compatible with mypy for static type checking. All public APIs include comprehensive type hints.

Running Type Checks

# Install mypy
pip install mypy

# Run type checking on your code
mypy your_script.py

Example with Type Hints

from typing import Dict, Any
from mailnow import MailnowClient

def send_welcome_email(client: MailnowClient, user_email: str) -> Dict[str, Any]:
    """Send a welcome email to a new user."""
    return client.send_email(
        from_email="welcome@yourcompany.com",
        to_email=user_email,
        subject="Welcome!",
        html="<h1>Welcome to our platform!</h1>"
    )

# mypy will catch type errors
client: MailnowClient = MailnowClient(api_key="mn_live_abc123")
response: Dict[str, Any] = send_welcome_email(client, "user@example.com")

API Reference

MailnowClient

Main client class for interacting with the Mailnow API.

__init__(api_key: str) -> None

Initialize the Mailnow client.

Parameters:

  • api_key (str): Your Mailnow API key (format: mn_live_* or mn_test_*)

Raises:

  • MailnowAuthError: If API key is invalid or missing

send_email(from_email: str, to_email: str, subject: str, html: str) -> Dict[str, Any]

Send an email via the Mailnow API.

Parameters:

  • from_email (str): Sender email address (must be valid format)
  • to_email (str): Recipient email address (must be valid format)
  • subject (str): Email subject line (cannot be empty)
  • html (str): HTML content of the email (cannot be empty)

Returns:

  • Dict[str, Any]: Response dictionary containing:
    • success (bool): Whether the email was successfully queued
    • message_id (str): Unique identifier for the message
    • status (str): Current status (e.g., "queued")

Raises:

  • MailnowValidationError: Invalid input parameters
  • MailnowAuthError: Authentication failure
  • MailnowRateLimitError: Rate limit exceeded
  • MailnowServerError: Server error (5xx)
  • MailnowConnectionError: Network connection error

Requirements

  • Python 3.12 or higher
  • httpx >= 0.27.0

Development

Installing Development Dependencies

pip install py-mailnow[dev]

Running Tests

pytest

Running Type Checks

mypy mailnow

Code Formatting

black mailnow tests
ruff check mailnow tests

License

This project is licensed under the MIT License.

Support

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Release files for py-mailnow 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for py-mailnow 0.1.1
File Size Uploaded
py_mailnow-0.1.1.tar.gz 77.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for py-mailnow 0.1.1
File Interpreter ABI Platform
py_mailnow-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 88.5 kB

Release files / py_mailnow-0.1.1.tar.gz

Download URL py_mailnow-0.1.1.tar.gz
Size 77.3 kB
Tags Source
SHA-256 checksum
How to use checksums
f529b12961222911d59eb48a9b06ff12dd22e49a6c6f4127179430dd5581022a
BLAKE2b-256 checksum
How to use checksums
bbf03cd41a2415314fa895bd6c3ed20fcc9016e76207fe735eaf4f74da288cf6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release files / py_mailnow-0.1.1-py3-none-any.whl

Download URL py_mailnow-0.1.1-py3-none-any.whl
Size 11.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
19fec350dea672ad56b88de9c10758c4c60c8995f679b513d356dd0c4b679797
BLAKE2b-256 checksum
How to use checksums
1e8f7f92ebdead5b24f5c436b56a926915e6630e4e9fd88eec71a31a030bd298
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page