Skip to main content

Official Python SDK for Postject email API

Project description

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

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

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.

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