Connect Mailsnail to your agent
Two ways to run it. Managed is the one to start with: you sign in, we hold the print-and-mail credentials, and your agent draws against a prepaid balance. Self-hosted is for people who already have a Click2Mail or Lob account and would rather use their own.
Managed — sign in, add a card, send
Nothing to install and no keys to paste. The server lives at https://api.mailsnail.dev/mcp. Two steps: add it, then start the sign-in from your client — adding a server registers it, but doesn't open the browser on its own.
1. Add the server
Claude Code, one line. Note -t http — this is a remote server, not an npm package.
claude mcp add -t http mailsnail https://api.mailsnail.dev/mcpClaude Desktop: Settings → Connectors → Add custom connector, and paste the same URL. Cursor and other clients that take a JSON config use the url form:
{
"mcpServers": {
"mailsnail": {
"url": "https://api.mailsnail.dev/mcp"
}
}
}2. Sign in
The server answers an unauthenticated call with a standard OAuth challenge, so your client knows where to send you and registers itself. You just approve it in the browser.
# In Claude Code, open the MCP panel:
/mcp
# Select "mailsnail" -> Authenticate.
# Your browser opens our sign-in page. Sign in (or create an
# account), approve access, and the tab hands the session back.
# "mailsnail" then reads: connected.Sign-in is email and password today. There is no separate account to create on this website — the account your agent authenticates against is the account.
3. Send something — and fund the balance when asked
You do not have to add a card up front. The first send tells you what it needs and hands back a link.
You: Ask your agent to mail something. For example —
"Send a letter to Jane Doe at 1 Main St, Brooklyn NY 11201
that says: thanks for the referral."
Agent: calls preview_letter -> shows you a proof PDF and the price
Agent: calls send_letter -> { "error": "payment_setup_required",
"setup_url": "https://checkout.stripe.com/..." }
You: open the setup_url, add a card, choose an opening balance.
Stripe handles the card; we never see the number.
Agent: retry send_letter -> { "id": "...", "status": "queued" }Why a balance instead of charging your card per letter
Card processing costs a fixed fee on every charge, on top of the percentage. On a $1.50 letter that fixed fee would eat a fifth of the price. Funding a balance once and drawing mail against it means one fixed fee instead of one per piece, which is what keeps cheap mail cheap. When the balance runs low we top it up from your saved card so an agent doesn't stall mid-task — you set the amounts, and you can switch it off in the billing portal. More on billing.
Tools your agent gets in managed mode
verify_address— USPS address validation. Free — never charges, never mails.preview_letter— Proof PDF plus the exact price, without charging or mailing. The recommended first step.send_letter— Mails a letter, drawn against your balance. Add extra_service: "certified" for tracking.send_postcard— Mails a postcard from a PDF you host (front and back combined).get_balance— Your balance, saved card, and auto-reload settings. Free.add_payment_method— Returns a link to add a first card, or to change an existing one.top_up— Adds funds from the card on file. Charges immediately, so agents should only call it when you ask.get_letter— Delivery status for a letter. Free.get_postcard— Delivery status for a postcard. Free.
list_letters and cancel_letter are not available in managed mode — they exist only on the self-hosted path below, where the underlying provider account is yours.
What a piece costs
Per piece, drawn from your balance. Certified mail with an electronic return receipt is $15.00. Ask your agent to call preview_letter and it will quote the exact price before anything is charged.
Self-hosted — bring your own mail provider
Run the open-source server yourself against your own Click2Mail or Lob account. There is no sign-in and no balance: your provider bills you directly, and we are not in the payment path at all. This is the mailsnail npm package over stdio.
Claude Code
claude mcp add mailsnail \
-e MAIL_PROVIDER=click2mail \
-e CLICK2MAIL_USERNAME=your-username \
-e CLICK2MAIL_PASSWORD=your-password \
-- npx -y mailsnailClaude Desktop and Cursor
Claude Desktop: claude_desktop_config.json (Settings → Developer → Edit Config). Cursor: ~/.cursor/mcp.json or the project's .cursor/mcp.json. Needs Node.js 18+.
{
"mcpServers": {
"mailsnail": {
"command": "npx",
"args": [
"-y",
"mailsnail"
],
"env": {
"MAIL_PROVIDER": "click2mail",
"CLICK2MAIL_USERNAME": "your-username",
"CLICK2MAIL_PASSWORD": "your-password"
}
}
}
}Codex CLI
Add to ~/.codex/config.toml.
[mcp_servers.mailsnail]
command = "npx"
args = ["-y", "mailsnail"]
[mcp_servers.mailsnail.env]
MAIL_PROVIDER = "click2mail"
CLICK2MAIL_USERNAME = "your-username"
CLICK2MAIL_PASSWORD = "your-password"Set MAIL_PROVIDER=lob with LOB_API_KEY to use Lob instead. Self-hosted mode adds list_letters (Lob only — Click2Mail has no list endpoint) and cancel_letter (a short window before the piece enters production). Source and provider docs are on GitHub.
HTTP API, no account
There is also an anonymous path for agents that can pay for themselves: post a letter, get a 402 with the price, retry with a Stripe Shared Payment Token for that amount. No sign-in, no balance, no account on our side.
Worth being straight about the tradeoff: most coding agents, including Claude Code, cannot mint a Shared Payment Token on their own today. If yours can't, use managed mode above — that is precisely the gap it was built to close. Settlement in USDC over x402 is planned, not shipped.
# Anonymous, no account: quote first, then pay for that exact piece.
# Your client has to be able to produce a Stripe Shared Payment Token.
curl -X POST https://api.mailsnail.dev/v1/letters \
-H "Content-Type: application/json" \
-d '{
"to": {
"name": "Jane Doe",
"address_line1": "1 Main St",
"address_city": "Brooklyn",
"address_state": "NY",
"address_zip": "11201"
},
"from": { "…same shape…": "" },
"body_text": "Hello from your agent."
}'
# -> 402 Payment Required
# {
# "status": 402,
# "payment_request": {
# "amount": 150, "currency": "usd", "methods": ["stripe.spt"],
# "idempotency_key": "…"
# }
# }
# Retry the identical request with a token for the quoted amount:
# "payment_token": "spt_…"
# -> 200 { id, status, receipt_url }Machine-readable everything
Full tool schemas live in /llms-full.txt and /openapi.json. If a model is reading this page cold, those are the two files it wants.
Stuck? Email hello@mailsnail.dev.