Introducing the Postscale Python SDK

Published on June 16, 2026

Send email and verify Postscale webhooks from Python with the official PyPI package.

Postscale now has an official Python SDK on PyPI: postscale.

The first release is built for server-side Python 3.10+ applications. It wraps the public Postscale API, keeps the same request fields you see in the REST docs, and adds the pieces most teams otherwise write by hand: result objects, attachment helpers, retry handling for idempotent requests, and webhook signature verification.

Install

pip install postscale

Set your API key in the environment:

POSTSCALE_API_KEY=ps_live_your_api_key

API keys should only be used from trusted server-side code. Do not ship them in browser bundles or mobile applications.

Send Your First Email

import os

from postscale import Postscale

postscale = Postscale(os.environ["POSTSCALE_API_KEY"])

result = postscale.emails.send({
    "from": "hello@yourdomain.com",
    "to": ["user@example.com"],
    "subject": "Welcome to Postscale",
    "html_body": "<strong>It works.</strong>",
})

if result.error:
    raise RuntimeError(result.error.message)

print(result.data["message_id"])

Before production sending, add and verify your sending domain in Postscale so SPF, DKIM, DMARC, and return-path bounce tracking are configured correctly. The Getting Started guide covers that flow end to end.

API-Native by Design

The SDK keeps Postscale request fields in snake_case.

That is intentional. The same payload works across SDK examples, REST examples, OpenAPI tooling, logs, and support conversations:

postscale.emails.send({
    "from": "orders@yourdomain.com",
    "to": ["customer@example.com"],
    "subject": "Receipt",
    "html_body": "<p>Thanks for your order.</p>",
    "text_body": "Thanks for your order.",
    "metadata": {
        "order_id": "ord_123",
    },
})

There is less translation layer to learn, and fewer edge cases where a field name differs between SDK and HTTP usage.

Result Objects Instead of Throw-Only Flows

Resource methods return PostscaleResult objects with data, error, and headers:

result = postscale.emails.send({
    "from": "hello@yourdomain.com",
    "to": ["user@example.com"],
    "subject": "Welcome",
    "html_body": "<strong>Hello</strong>",
})

if result.error:
    print(result.error.code, result.error.message, result.headers.request_id)
    raise SystemExit(1)

print(result.data["status"])

The SDK does not automatically retry non-idempotent email sends. That keeps applications from accidentally duplicating customer email until the send API has an explicit idempotency contract.

Attachments

For file attachments, use the helper instead of manually base64-encoding the file:

from postscale import Postscale, attachment_from_file

postscale = Postscale()

result = postscale.emails.send({
    "from": "billing@yourdomain.com",
    "to": ["customer@example.com"],
    "subject": "Invoice #1234",
    "html_body": "<p>Your invoice is attached.</p>",
    "attachments": [
        attachment_from_file("./invoice-1234.pdf", "application/pdf"),
    ],
})

if result.error:
    raise RuntimeError(result.error.message)

The SDK checks the documented attachment limits before sending: 10 attachments, 25 MB per attachment, and 50 MB total decoded attachment payload.

Webhook Verification

Postscale signs webhook deliveries with X-Postscale-Signature. The SDK verifies the timestamped t=...,v1=... format and supports multiple secrets during rotation windows:

from postscale import verify_webhook_signature

result = verify_webhook_signature(
    raw_body,
    request.headers.get("X-Postscale-Signature"),
    [current_secret, previous_secret],
)

if not result.valid:
    return "invalid", 401

Use the raw request body bytes for verification. Do not parse JSON and re-serialize it before verifying the signature.

What Is Included

The initial Python SDK covers public product APIs:

  • emails
  • domains
  • dkim
  • aliases
  • inbound
  • stats
  • warming
  • suppressions
  • webhooks
  • templates
  • usage
  • trust

It intentionally does not include billing, invoices, onboarding, browser auth, MFA, API-key management, admin routes, Stripe webhooks, unsubscribe endpoints, or contact forms.

What Is Next

Python joins the official Node.js and TypeScript SDK. The roadmap continues with PHP/Laravel, Go, Ruby, Java/Kotlin, .NET, and Rust once the public OpenAPI contract is ready for each ecosystem.

Start with the SDKs and HTTP Clients guide, or install the package from PyPI.