Official Python client for the Reletter newsletter API. Search 6M+ email newsletters across Substack, LinkedIn, Ghost, and more. Fetch metadata and contacts, pull issue text, and build alerts and pipelines.
Thin, typed wrapper around the Reletter HTTP API. Ships with a reletter CLI for shell scripts and AI coding agents. If you want Reletter inside an AI assistant via Model Context Protocol, use the Reletter MCP Server.
- Find newsletters to contact about getting your product, tool, or book featured — filter by audience size, topic, or platform, then pull verified contact emails in one pass
- Build sponsorship, cross-promotion, and PR target lists, then export contacts to your CRM
- Enrich a CRM with newsletter metadata, subscriber numbers, and contacts
- Monitor brand or keyword mentions by polling
search.issueswith a rollingthreshold - Pull subscriber numbers, engagement, language, country, and rankings for any newsletter
- Grab daily Substack / LinkedIn / Reletter chart data
- Feed full newsletter issue text into your own LLM pipeline
- Power a newsletter discovery app: search, autocomplete, similar newsletters
pip install reletter # SDK (and CLI)
pipx install reletter # CLI in an isolated venv (recommended for the CLI)Python 3.8+.
pip install reletter also installs a reletter command. Every method on the Python client has a CLI equivalent. Authentication is via RELETTER_API_KEY in the environment. Output is JSON on stdout, structured errors on stderr.
export RELETTER_API_KEY=your_api_key
# Look up a publication
reletter publications get doomberg | jq '.publication.name'
# Search with Stripe-style filters
reletter search publications \
--query "climate" \
--filters '{"subscribers":{"gte":5000},"active":true}'
# Search newsletter issues for the last 7 days
reletter search issues --query "openai" --threshold 604800
# Check your quota
reletter account quotaExit codes: 0 success, 1 API or network error, 2 usage error (bad flags), 4 authentication error, 5 server error (5xx).
Run reletter --help for the full command tree, or reletter <group> --help (e.g. reletter publications --help) for commands inside a group. The seven groups match the Python client: search, publications, issues, contacts, charts, common, account.
Grab an API key from reletter.com/developers.
from reletter import Reletter
client = Reletter(api_key="your_api_key")
# Look up a publication by its Reletter slug
publication = client.publications.get("doomberg")
print(publication["publication"]["name"], publication["publication"]["subscribers"])
# Search for newsletters with filters
results = client.search.publications(
query="artificial intelligence",
filters={"subscribers": {"gte": 5000}, "active": True},
per_page=25,
)
for p in results["publications"]:
print(p["id"], p["name"])
# Auto-paginate
for p in client.search.iter_publications(query="climate", limit=200):
print(p["id"])
# Pull contacts
contacts = client.contacts.get("doomberg")
for c in contacts["contacts"]["email"]:
print(c["email"], c["verification_status"])The client also picks up RELETTER_API_KEY from the environment:
import os
os.environ["RELETTER_API_KEY"] = "your_api_key"
from reletter import Reletter
client = Reletter()import asyncio
from reletter import AsyncReletter
async def main():
async with AsyncReletter() as client:
publication = await client.publications.get("doomberg")
async for p in client.search.iter_publications(query="ai", limit=100):
print(p["name"])
asyncio.run(main())Search endpoints accept Stripe-style filter dicts, raw DSL strings, or lists of clauses:
# Dict (preferred)
client.search.publications(filters={"subscribers": {"gte": 10000}, "active": True})
# Raw DSL string
client.search.publications(filters="subscribers:gte:10000,active:is:true")
# List of raw clauses
client.search.publications(filters=["subscribers:gte:10000", "active:is:true"])See https://reletter.com/developers for the available fields and operators.
from reletter import (
Reletter,
AuthenticationError,
BadRequestError,
RateLimitError,
)
try:
client = Reletter()
client.publications.get("doomberg")
except AuthenticationError:
... # invalid / missing API key
except RateLimitError:
... # 429 — back off and retry
except BadRequestError as e:
print(e.message, e.body)The client retries automatically on 429 and 5xx responses (default 2 retries, exponential backoff). Configure with Reletter(max_retries=N) or 0 to disable.
MIT. Copyright Reletter.