Skip to main content

NorthRelay Python SDK

Official Python SDK for the NorthRelay Platform API - Send transactional emails with ease.

PyPI version Python 3.9+ License: MIT

Features

  • 100% Feature Parity - All 20 resources from TypeScript SDK
  • Async/await support - Native asyncio for FastAPI, async frameworks
  • Type-safe - Full Pydantic v2 models with IDE autocomplete
  • Automatic retries - Exponential backoff with configurable retry logic
  • Rate limiting - Built-in rate limit tracking and error handling
  • Comprehensive error handling - Structured exceptions for all error cases
  • Production-ready - Used in production by MemoryRelay and others

Installation

pip install northrelay

With webhook signature verification:

pip install northrelay[webhooks]

Quick Start

from northrelay import NorthRelay

# Initialize client
client = NorthRelay(api_key="nr_live_...")

# Send an email
response = await client.emails.send(
    from_={"email": "noreply@example.com", "name": "Example"},
    to=[{"email": "user@example.com"}],
    content={
        "subject": "Welcome!",
        "html": "<h1>Welcome to our service!</h1>",
        "text": "Welcome to our service!",
    },
)

print(f"Email sent! Message ID: {response.message_id}")

Usage

Send Email with Template

from northrelay import NorthRelay

client = NorthRelay(api_key="nr_live_...")

# Send using template
response = await client.emails.send_template(
    template_id="tpl_abc123",
    to=[{"email": "user@example.com", "name": "John"}],
    variables={
        "name": "John",
        "verification_code": "123456",
        "expires_at": "2024-12-31",
    },
    from_={"email": "noreply@example.com", "name": "Example"},
    theme_id="theme_xyz789",  # Optional brand theme
)

Send Batch Emails

from northrelay import NorthRelay, SendEmailRequest

client = NorthRelay(api_key="nr_live_...")

emails = [
    SendEmailRequest(
        from_={"email": "noreply@example.com"},
        to=[{"email": f"user{i}@example.com"}],
        content={"subject": "Update", "html": f"<p>Hello user {i}!</p>"},
    )
    for i in range(100)
]

result = await client.emails.send_batch(emails)
print(f"Sent {result['accepted_count']} of {len(emails)} emails")

Schedule Email for Later

from northrelay import NorthRelay, SendEmailRequest
from datetime import datetime, timedelta

client = NorthRelay(api_key="nr_live_...")

future_time = datetime.now() + timedelta(hours=2)

request = SendEmailRequest(
    from_={"email": "noreply@example.com"},
    to=[{"email": "user@example.com"}],
    content={"subject": "Scheduled Email", "html": "<p>This was scheduled!</p>"},
)

result = await client.emails.schedule(request, scheduled_for=future_time)
print(f"Scheduled email with ID: {result['schedule_id']}")

Error Handling

from northrelay import (
    NorthRelay,
    AuthenticationError,
    ValidationError,
    RateLimitError,
    QuotaExceededError,
    ServerError,
)

client = NorthRelay(api_key="nr_live_...")

try:
    await client.emails.send(...)
    
except AuthenticationError:
    print("Invalid API key")
    
except ValidationError as e:
    print(f"Validation error: {e.message}")
    print(f"Errors: {e.errors}")
    
except RateLimitError as e:
    print(f"Rate limited! Retry after {e.retry_after} seconds")
    await asyncio.sleep(e.retry_after)
    
except QuotaExceededError as e:
    print(f"Quota exceeded: {e.quota_used}/{e.quota_limit}")
    
except ServerError as e:
    print(f"Server error ({e.status_code}): {e.message}")

Rate Limit Tracking

client = NorthRelay(api_key="nr_live_...")

await client.emails.send(...)

# Check rate limit info from last request
rate_limit = client.get_rate_limit_info()
if rate_limit:
    print(f"Remaining: {rate_limit.remaining}/{rate_limit.limit}")
    print(f"Resets at: {rate_limit.reset}")

Context Manager (Auto-close)

async with NorthRelay(api_key="nr_live_...") as client:
    await client.emails.send(...)
    # HTTP client auto-closes on exit

Configuration

client = NorthRelay(
    api_key="nr_live_...",
    base_url="https://app.northrelay.ca",  # Default
    timeout=30.0,                           # Request timeout (seconds)
    max_retries=3,                          # Retry attempts
    retry_delay=1.0,                        # Initial retry delay (seconds)
    max_retry_delay=10.0,                   # Max retry delay (seconds)
)

Retry Behavior

The SDK automatically retries on:

  • ✅ Network errors (connection timeout, DNS failure)
  • ✅ Server errors (500, 502, 503, 504)
  • ✅ Rate limits (429) - with exponential backoff

Does not retry on:

  • ❌ Authentication errors (401)
  • ❌ Validation errors (400)
  • ❌ Not found errors (404)

FastAPI Integration

from fastapi import FastAPI
from northrelay import NorthRelay

app = FastAPI()
client = NorthRelay(api_key="nr_live_...")

@app.post("/send-welcome-email")
async def send_welcome(email: str, name: str):
    response = await client.emails.send_template(
        template_id="tpl_welcome",
        to=[{"email": email, "name": name}],
        variables={"name": name},
    )
    return {"message_id": response.message_id}

@app.on_event("shutdown")
async def shutdown():
    await client.close()

Development Status

Current Version: 1.1.0 - 100% Complete! ✅

All Resources Implemented ✅

Resource Status Description
Emails Send, schedule, batch, validate
Templates CRUD, preview, variable extraction
Domains Add, verify, DNS records
Webhooks CRUD, secret rotation, test delivery
Campaigns CRUD, approval workflow, sending
Contacts CRUD, lists, bulk operations, CSV import
Brand Themes CRUD, multi-theme support
API Keys Create, list, revoke
Events Track email events, analytics
Analytics Heatmaps, geographic, provider stats
Metrics Delivery metrics, summaries
Suppressions Block list management
Suppression Groups Unsubscribe groups
Subusers Subaccount management
IP Pools IP pool management
Dedicated IPs IP allocation, warmup
Identity Sender identity management
Inbound Inbound email domains
Admin Admin utilities
Keys DKIM key management

Total: 20/20 resources implemented 🎉

Feature Parity with TypeScript SDK

100% Complete - All methods from TypeScript SDK v1.1.0 implemented

API Documentation

Full API documentation: docs.northrelay.ca

Requirements

  • Python 3.9+
  • httpx >= 0.27.0
  • pydantic >= 2.6.0
  • tenacity >= 8.2.0
  • python-dateutil >= 2.8.0

Support

License

MIT License - see LICENSE file for details.

Contributing

Contributions welcome! Please open an issue first to discuss proposed changes.


Made with ❤️ by the NorthRelay team

Download files

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

Source Distribution

northrelay-1.6.0.tar.gz (31.8 kB view details)

Uploaded Source

Built Distribution

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

northrelay-1.6.0-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file northrelay-1.6.0.tar.gz.

File metadata

  • Download URL: northrelay-1.6.0.tar.gz
  • Upload date:
  • Size: 31.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for northrelay-1.6.0.tar.gz
Algorithm Hash digest
SHA256 a3fc1ad29c54c6143111caef992534a1f995247a59c0b316ab6cfbcf289a5c18
MD5 8997a70c120b1ecab09ec6ffbfbe9eef
BLAKE2b-256 5e11dee67d2b7fc212247c822912b46cca6456cb729f35e12cc7138c5a4e7cb6

See more details on using hashes here.

File details

Details for the file northrelay-1.6.0-py3-none-any.whl.

File metadata

  • Download URL: northrelay-1.6.0-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for northrelay-1.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bdde65f9b41d3c93c73867927a318013527d8486026b19aeb04d2d10998e51fe
MD5 dc82a11f11e3d875385487041e94204a
BLAKE2b-256 dfb9b044b096b4f8c29dadb2d31ba33c0c416a0a6a9b1e086b64fdf930675d9d

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.6.0 This release

2 files

1.5.1

2 files

1.5.0

2 files

1.4.0

2 files

1.3.0

2 files

1.2.0

2 files

1.1.0

2 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