Skip to main content

Postject Python SDK

Official Python SDK for the Postject email API.

Installation

pip install postject

Quick Start

from postject import Postject

client = Postject(api_key="pk_live_your_api_key_here")

# Send a simple email
result = client.send({
    "to": "customer@example.com",
    "subject": "Welcome to our platform!",
    "html": "<h1>Welcome!</h1><p>Thanks for signing up.</p>"
})

print(f"Message ID: {result.id}")
print(f"Status: {result.status}")

Features

✅ Full type hints (Pydantic models) ✅ Sync and async support ✅ Automatic retry on rate limits ✅ Comprehensive error handling ✅ All API endpoints covered

Configuration

client = Postject(
    api_key="pk_live_your_api_key_here",
    base_url="https://api.postject.com",  # optional
    timeout=30,  # optional, in seconds
    retries=3,   # optional, for rate limits
)

Sending Emails

Simple Email

result = client.send({
    "to": "user@example.com",
    "from": "noreply@yourapp.com",  # optional if identity configured
    "subject": "Hello World",
    "html": "<p>This is a test email</p>",
    "text": "This is a test email",  # optional plain text
})

Multiple Recipients

client.send({
    "to": ["user1@example.com", "user2@example.com", "user3@example.com"],
    "subject": "Bulk announcement",
    "html": "<p>Important update</p>",
})

Using Templates

result = client.send_with_template(
    template_id="template_id_here",
    to="user@example.com",
    variables={
        "name": "John Doe",
        "order_number": "12345",
        "order_total": "$99.00",
    },
    stream_id="transactional_stream_id",  # optional
)

Type-Safe Request

from postject import SendEmailRequest

request = SendEmailRequest(
    to="user@example.com",
    subject="Order Confirmation",
    html="<p>Your order has been confirmed</p>",
    tags=["order", "confirmation"],
    metadata={"order_id": "12345"},
    idempotency_key="order_12345",  # prevents duplicates
    analyze_content=True,  # check spam score
)

result = client.send(request)

Managing Resources

Servers

# List all servers
servers = client.get_servers()

# Create a server
server = client.create_server("Production Server")

# Delete a server
client.delete_server("server_id")

Message Streams

# List streams
streams = client.get_streams("server_id")

# Create a stream
stream = client.create_stream(
    server_id="server_id",
    name="Transactional Emails",
    slug="transactional",
    description="Order confirmations, password resets, etc.",
    stream_type="transactional",
)

# Delete a stream
client.delete_stream("server_id", "stream_id")

Templates

# List templates
templates = client.get_templates("server_id")

# Create a template
template = client.create_template(
    server_id="server_id",
    name="Welcome Email",
    subject="Welcome to {{company_name}}!",
    html="<h1>Welcome {{user_name}}!</h1><p>Thanks for signing up.</p>",
)

# Update a template
client.update_template(
    server_id="server_id",
    template_id="template_id",
    subject="Updated subject",
    html="<p>Updated content</p>",
)

# Delete a template
client.delete_template("server_id", "template_id")

Webhooks

# Create a webhook
webhook = client.create_webhook(
    stream_id="stream_id",
    url="https://yourapp.com/webhooks/postject",
    events=["delivered", "bounced", "complained"],  # or ["*"] for all
)

print(f"Webhook secret: {webhook.secret}")  # Use for signature verification

# List webhooks
webhooks = client.get_webhooks("stream_id")

# Get webhook logs
logs_data = client.get_webhook_logs("webhook_id", limit=50, offset=0)
print(f"Total logs: {logs_data['total']}")
for log in logs_data['logs']:
    print(f"{log.event_type}: {log.status_code}")

# Test a webhook
client.test_webhook("webhook_id")

# Delete a webhook
client.delete_webhook("stream_id", "webhook_id")

Message Tracking

# Get message details
message = client.get_message("message_id")
print(f"Status: {message.status}")
print(f"Route: {message.route_name}")
print(f"Latency: {message.latency_ms}ms")

# Get message events (full timeline)
events = client.get_message_events("message_id")
for event in events:
    print(f"{event.type} at {event.timestamp}")

API Key Management

# List API keys
keys = client.get_api_keys()

# Create a new key
new_key = client.create_api_key(
    name="Production Key",
    expires_in_days=365,
)
print(f"New API key: {new_key.key}")  # SAVE THIS!

# Revoke a key
client.revoke_api_key("key_id")

# Rotate a key
rotated_key = client.rotate_api_key("old_key_id", name="New Production Key")

Content Analysis

# Analyze content before sending
analysis = client.analyze_content(
    subject="Your subject line",
    html="<html><body>Email content</body></html>",
)

print(f"Overall score: {analysis.overall_score}/100")
print(f"Spam score: {analysis.spam_score}/100")

for issue in analysis.issues:
    print(f"[{issue.severity}] {issue.message}")
    print(f"  Suggestion: {issue.suggestion}")

for recommendation in analysis.recommendations:
    print(f"✓ {recommendation}")

Analytics

# Get server overview
analytics = client.get_server_analytics("server_id")

print(f"Total sent: {analytics.total_sent}")
print(f"Delivery rate: {analytics.delivery_rate * 100:.2f}%")
print(f"Bounce rate: {analytics.bounce_rate * 100:.2f}%")
print(f"Avg latency: {analytics.avg_latency}ms")

Error Handling

from postject import (
    PostjectError,
    AuthenticationError,
    RateLimitError,
    ValidationError,
    NotFoundError,
    ServerError,
)

try:
    client.send({"to": "user@example.com", "subject": "Test", "html": "..."})
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except ValidationError as e:
    print(f"Validation error: {e.response}")
except NotFoundError:
    print("Resource not found")
except ServerError as e:
    print(f"Server error: {e.status_code}")
except PostjectError as e:
    print(f"API error: {e.message}")

Async Support

import asyncio
from postject import AsyncPostject

async def send_email():
    async with AsyncPostject(api_key="your_api_key") as client:
        result = await client.send({
            "to": "user@example.com",
            "subject": "Async Email",
            "html": "<p>Sent asynchronously</p>",
        })
        print(f"Sent: {result.id}")

asyncio.run(send_email())

Context Manager

# Automatic client cleanup
with Postject(api_key="your_api_key") as client:
    result = client.send({
        "to": "user@example.com",
        "subject": "Test",
        "html": "<p>Email body</p>",
    })
# Client automatically closed

Type Hints

Full type hints using Pydantic:

from postject.types import (
    SendEmailRequest,
    SendEmailResponse,
    Server,
    MessageStream,
    Template,
    Webhook,
    Message,
    Event,
)

def send_welcome_email(email: str) -> SendEmailResponse:
    client = Postject(api_key="your_key")
    request = SendEmailRequest(
        to=email,
        subject="Welcome!",
        html="<p>Welcome to our platform</p>",
    )
    return client.send(request)

Examples

# Send transactional email
client.send({
    "to": "customer@example.com",
    "subject": "Your order #12345 has shipped",
    "html": """
        <h2>Order Shipped!</h2>
        <p>Your order #12345 is on its way.</p>
        <p>Tracking: ABC123XYZ</p>
    """,
    "tags": ["shipping", "order"],
    "metadata": {"order_id": "12345"},
})

# Send password reset
client.send_with_template(
    template_id="password_reset_template",
    to="user@example.com",
    variables={
        "reset_link": "https://app.com/reset?token=abc123",
        "expires_in": "1 hour",
    },
)

# Batch send with template
users = [
    {"email": "user1@example.com", "name": "Alice"},
    {"email": "user2@example.com", "name": "Bob"},
]

for user in users:
    client.send_with_template(
        template_id="newsletter_template",
        to=user["email"],
        variables={"name": user["name"]},
        stream_id="newsletter_stream",
    )

Requirements

  • Python 3.8+
  • httpx>=0.24.0
  • pydantic>=2.0.0

Support

License

MIT

Download files

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

Source Distribution

postject-1.0.1.tar.gz (12.0 kB view details)

Uploaded Source

Built Distribution

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

postject-1.0.1-py3-none-any.whl (10.2 kB view details)

Uploaded Python 3

File details

Details for the file postject-1.0.1.tar.gz.

File metadata

  • Download URL: postject-1.0.1.tar.gz
  • Upload date:
  • Size: 12.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for postject-1.0.1.tar.gz
Algorithm Hash digest
SHA256 33832c5f107d811303e23de07178b119870151f8d252dbdec92d478e8bd1e14a
MD5 bee65da6be467debe8f91975c9af267a
BLAKE2b-256 184623178c257b15d10464454874e0408b2b62017c989b1002be7394792f7fe3

See more details on using hashes here.

File details

Details for the file postject-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: postject-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 10.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for postject-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 10761aa9682bb339b4f4316ab4c251ad06a5a291e2cf85bffb9fc1e4c3a048b1
MD5 fae820371500e400707bd39466253f6a
BLAKE2b-256 8af158e02073d8f5237a7e68950f569d1b9a709ca343d4d7b038c0b43bfc9bf1

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 files

1.0.0

2 files

Supported by

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