Skip to content

Getting Started

Greg Svoboda edited this page Mar 4, 2026 · 1 revision

Getting Started

Prerequisites

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.

Installation

pip install postmark-python

(PyPI Coming Soon)

Python 3.10 or higher is required.

Quick Start

The library is fully async. All API calls must be awaited inside an async context.

Send Your First Email

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.

Two Client Types

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")

Using Environment Variables

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

Dict vs. Model Input

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!",
    )
)

Advanced Configuration

Custom Timeout

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.

Custom Base URL

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")

Retry Behavior

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 AccountClient defaults (timeout=30, retries=3), a single call that repeatedly times out can block for up to ~90 seconds before raising. ServerClient defaults (timeout=5, retries=3) cap this at ~15 seconds. Tune both values to match your application's latency budget.

SSL Verification

SSL verification can be disabled for development or testing. Do not disable in production.

import os
os.environ["POSTMARK_SSL_VERIFY"] = "false"

Debug Logging

import logging
logging.getLogger("postmark").setLevel(logging.DEBUG)

Next Steps

Clone this wiki locally