-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
Before you begin, you'll need:
- A Postmark account
- A Server API token (for sending email and server-level operations)
- An Account API token (for account-level operations like managing domains and servers)
- A verified sender signature or domain
You can find your tokens under API Tokens in the Postmark app.
pip install postmark-python
(PyPI Coming Soon)
Python 3.10 or higher is required.
The library is fully async. All API calls must be awaited inside an async context.
import asyncio
import postmark
async def main():
async with postmark.ServerClient("your-server-token") as client:
response = await client.outbound.send({
"sender": "you@verified-domain.com",
"to": "recipient@example.com",
"subject": "Hello from Postmark!",
"text_body": "This is my first email via postmark-python.",
"html_body": "<p>This is my first email via <strong>postmark-python</strong>.</p>",
})
print(f"Sent! Message ID: {response.message_id}")
print(f"Accepted: {response.success}") # True when error_code == 0
asyncio.run(main())Note: You must use a verified sender address and a valid server token from your account.
Using the client as an async context manager (async with) is recommended. It ensures the underlying HTTP connection pool is cleanly closed when the block exits. For long-lived processes (servers, workers) you can also instantiate the client once and call await client.close() when shutting down.
| Client | Token | Use for |
|---|---|---|
ServerClient |
Server API token | Sending email, bounces, templates, stats, webhooks, streams |
AccountClient |
Account API token | Domains, sender signatures, managing servers, data removals |
import postmark
# Server-level operations
server_client = postmark.ServerClient("your-server-token")
# Account-level operations
account_client = postmark.AccountClient("your-account-token")It's best practice to store tokens in environment variables rather than hard-coding them.
import asyncio
import os
import postmark
# python-dotenv is not bundled with the SDK — install it separately if needed:
# pip install python-dotenv
from dotenv import load_dotenv
load_dotenv()
client = postmark.ServerClient(os.environ["POSTMARK_SERVER_TOKEN"])A .env file might look like:
POSTMARK_SERVER_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
POSTMARK_ACCOUNT_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
POSTMARK_SENDER_EMAIL=you@verified-domain.com
Most methods accept either a plain dict or a typed Pydantic model. Using models gives you IDE autocompletion and catches errors before they reach the API.
from postmark import Email
# Using a dict
await client.outbound.send({
"sender": "you@example.com",
"to": "recipient@example.com",
"subject": "Hello",
"text_body": "Hello!",
})
# Using a model (recommended)
await client.outbound.send(
Email(
sender="you@example.com",
to="recipient@example.com",
subject="Hello",
text_body="Hello!",
)
)Default timeouts differ by client: ServerClient defaults to 5 seconds, AccountClient to 30 seconds. Override per instance:
client = postmark.ServerClient("your-server-token", timeout=60.0)timeout must be a positive number — passing 0 or a negative value raises PostmarkException immediately at construction.
Override the API base URL — useful for pointing at a local mock server during tests:
client = postmark.ServerClient("your-server-token", base_url="http://localhost:8080")The client automatically retries on RateLimitException, ServerException, and TimeoutException using exponential backoff with jitter. By default it retries up to 3 times. Adjust with the retries parameter:
# Retry up to 5 times before raising
client = postmark.ServerClient("your-server-token", retries=5)
# Disable retries entirely
client = postmark.ServerClient("your-server-token", retries=0)retries must be a non-negative integer — passing a negative value raises PostmarkException immediately at construction.
Worst-case blocking time: With
AccountClientdefaults (timeout=30,retries=3), a single call that repeatedly times out can block for up to ~90 seconds before raising.ServerClientdefaults (timeout=5,retries=3) cap this at ~15 seconds. Tune both values to match your application's latency budget.
SSL verification can be disabled for development or testing. Do not disable in production.
import os
os.environ["POSTMARK_SSL_VERIFY"] = "false"import logging
logging.getLogger("postmark").setLevel(logging.DEBUG)- Email Sending — Attachments, batch sends, tracking options
- Templates — Send with pre-built templates
- Error Handling — Handle API errors gracefully
- Postmark API Reference