Introducing the Postscale Python SDK
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:
emailsdomainsdkimaliasesinboundstatswarmingsuppressionswebhookstemplatesusagetrust
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.