Skip to main content

pidgeon

The Python client for the Pidgeon email API — mailboxes your code creates, on a domain you own.

Generated from openapi.json, the same document the TypeScript client is generated from, so an operation has the same name in both: messages_send here is messagesSend there.

pip install pidgeon

Sending

An API key goes in PIDGEON_API_KEY. Every call takes the client; nothing is global.

import os

from pidgeon import AuthenticatedClient
from pidgeon.api.messages import messages_send
from pidgeon.models import Error, MessagesSendBody

client = AuthenticatedClient(
    base_url="https://pidgeon.ai/api/v1",
    token=os.environ["PIDGEON_API_KEY"],
)

result = messages_send.sync(
    client=client,
    body=MessagesSendBody(
        from_="hello@yourdomain.com",
        to=["priya@example.com"],
        subject="Your invoice",
        text="Attached, payable within 30 days.",
    ),
)

if isinstance(result, Error):
    raise RuntimeError(result.error.message)

Errors come back, they are not raised. Every call returns the success model or Error or None, so an isinstance check is the shape of a correct caller. Error.error carries the API's own code, a message written for a person and safe to show one, and a field when one input was at fault.

from_ and type_ carry a trailing underscore, because from and type are reserved in Python. The wire names are unchanged.

Every operation also has asyncio, and sync_detailed / asyncio_detailed variants that return the whole Response with its status and headers.

Receiving

Mail arriving at an address your code owns becomes an event, and your endpoint is called with a signed payload. Verify before you parse — an unverified payload is an unauthenticated POST that claims a message arrived.

from pidgeon.webhooks import verify_webhook

event = verify_webhook(
    raw_body=request.body,  # the exact bytes, before any json.loads
    headers=request.headers,
    secret=os.environ["PIDGEON_WEBHOOK_SECRET"],
)

raw_body must be the bytes we sent. Parse the JSON after verifying — re-serialising changes key order and the signature will not match. verify_webhook raises rather than returning a boolean, rejects a timestamp outside five minutes before it looks at the signature, and compares in constant time.

The event carries ids, never a body. Exchange one for the content with messages_get.

Creating an address

from pidgeon.api.identities import identities_create
from pidgeon.models import IdentitiesCreateBody

identities_create.sync(
    client=client,
    body=IdentitiesCreateBody(
        address="receipts@yourdomain.com",
        type_="agent",
        send_policy="reply_only",
    ),
)

Say where with address, domain or domain_id — one of the three. Every address you already have carries its domain_id, which is what to use when you are on the shared domain and own nothing to list.

send_policy="reply_only" makes an address structurally unable to write to anybody who has not written to it first, which is the right default for software.

Pagination

A list returns a page, not an iterator — deliberately. An iterator that hides pagination also hides the rate limit pagination is subject to.

from pidgeon.api.events import events_list

cursor = None
while True:
    page = events_list.sync(client=client, cursor=cursor)
    for event in page.data:
        handle(event)

    cursor = page.next_cursor
    if cursor is None:
        break

What this deliberately does not do

No retry policy, no queue, no caching, no auto-paginating iterator. Those are decisions that belong to your application — an SDK that makes them for you is one you eventually work around.

Versioning

Versioned independently of the API. The API is /v1; this package is 1.x, and semver applies to its own surface.

Full reference: pidgeon.ai/docs. MIT.

Metadata

Release files for pidgeon 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pidgeon 1.2.0
File Size Uploaded
pidgeon-1.2.0.tar.gz 123.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pidgeon 1.2.0
File Interpreter ABI Platform
pidgeon-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 485.4 kB

Release files / pidgeon-1.2.0.tar.gz

Download URL pidgeon-1.2.0.tar.gz
Size 123.8 kB
Tags Source
SHA-256 checksum
How to use checksums
b55947624e0c9e310ce54c0108f1e15294107c686f79044d49b701fc6c649289
BLAKE2b-256 checksum
How to use checksums
ff72b181e13dfcd3bee9b1113987bf4ff5d0a67620efc90749f994f867fea476
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / pidgeon-1.2.0-py3-none-any.whl

Download URL pidgeon-1.2.0-py3-none-any.whl
Size 361.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d241370d533a0050c22087179aebc4bb4b3c89d36d092b7ed87ea71a8ed287a2
BLAKE2b-256 checksum
How to use checksums
2c80659e5f8d6e92430fce73821789a0fd42d36e08f5ecd51d88e309f419a1f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

1.14.1

2 release files

1.14.0

2 release files

1.13.0

2 release files

1.12.0

2 release files

1.11.0

2 release files

1.9.0

2 release files

1.8.0

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

This release

1.2.0 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page