New: campaigns, automations and product emails in the same account. Meet Postal
Sign in Create account

Free email API

Free email API to send from your code

One POST /emails request sends the email. REST API with an API key, SDKs for Node.js and PHP, batch sending, scheduling and webhooks, all on the Free plan.

Free plan, no credit card

POST /emails
curl -X POST https://api.postal.so/emails \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Loja Exemplo <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your order #10482 is out for delivery",
    "html": "<p>Order <b>#10482</b> is on its way.</p>"
  }'
200Returns the email id

No cost

What the Free plan includes

The numbers come straight from the plan, always up to date.

1.500emails per month
50emails per day
5requests per second
1sending domain

Resources

Everything the API does

The features of an email API for your product, without asking for a paid plan.

Single and batch sending

One email per request, or up to 100 in one. In a batch, either all are queued or none are.

Scheduling

Pass scheduled_at with a date and time up to 30 days ahead.

Templates with variables

Send with template and variables: the HTML stays in the dashboard and your code only sends the values.

Webhooks and events

Receive delivery, bounce, open, click and complaint in your system, with a signature to verify.

Idempotency and retry

Resend without fear of duplicating: the idempotency key guarantees a single send.

MCP server

Connect Claude, Cursor and other AI tools to your account through the MCP server.

See how to connect

How to start

Send your first email in 3 steps

01

Create the account and verify the domain

In the dashboard, under Domains, add the domain and create the DNS records shown.

Getting started
02

Create an API key

Under API keys, create a send-only key and store it in POSTAL_API_KEY.

Authentication
03

Make a POST /emails

Use the example alongside (cURL, Node.js, PHP or Python) with a sender from your verified domain.

API reference

Code

Examples in several languages

Swap in your key and sender.

curl
curl -X POST https://api.postal.so/emails \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Loja Exemplo <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your order #10482 is out for delivery",
    "html": "<p>Order <b>#10482</b> is on its way.</p>"
  }'
postal-so
import { Postal } from 'postal-so'

const postal = new Postal() // reads POSTAL_API_KEY

const { id } = await postal.emails.send(
  {
    from: 'My company <[email protected]>',
    to: '[email protected]',
    subject: 'Welcome!',
    html: '<p>Great to have you here.</p>',
    text: 'Great to have you here.',
  },
  { idempotencyKey: 'welcome-42' },
)
postal-php
use Postal\Client;

$postal = new Client(); // reads POSTAL_API_KEY

$result = $postal->emails->send([
    'from' => 'My company <[email protected]>',
    'to' => '[email protected]',
    'subject' => 'Welcome!',
    'html' => '<p>Great to have you here.</p>',
]);
requests
import os
import requests

response = requests.post(
    "https://api.postal.so/emails",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "from": "Loja Exemplo <[email protected]>",
        "to": ["[email protected]"],
        "subject": "Your order #10482 is out for delivery",
        "html": "<p>Order <b>#10482</b> is on its way.</p>",
    },
    timeout=10,
)
data = response.json()
POST /emails
{
  "from": "Loja Exemplo <[email protected]>",
  "to": "[email protected]",
  "template": {
    "id": "order-shipped",
    "variables": { "NAME": "Ana", "ORDER": "10482" }
  }
}

Compatible

Already using Resend? Just swap the URL and the key

Postal's API uses the same features and formats, so you can keep the SDK you already have.

Before and after
Antes
  base URL: https://api.resend.com
  chave:    re_…

Depois
  base URL: https://api.postal.so
  chave:    ps_…

See the full guide

Questions about the free email API

Is Postal's email API free?

Yes. The Free plan includes the complete API: 1,500 emails per month and 50 per day, with one domain and 5 requests per second. There is no trial period and no credit card.

What is the request limit?

On the Free plan, 5 requests per second per team, across all keys. Batch sending helps: 100 emails count as one request. Every response carries the X-RateLimit-* headers.

How do I authenticate?

With an API key in the Authorization: Bearer ps_… header. Create a send-only key for your system and store it in an environment variable, never in the browser.

Is there an SDK?

Yes: postal-so for Node.js and TypeScript (npm install postal-so) and postal-so/postal-php for PHP and Laravel (composer require postal-so/postal-php), with typed errors, idempotency and retry. For other languages, the API is HTTP with JSON.

Can I use the Resend SDK?

Yes. Postal's API uses the same features and formats: point the base URL to https://api.postal.so and use your Postal key. See the guide to migrating from Resend.

Can I send from any address?

Only from domains you have verified. You add the domain in the dashboard, create the DNS records shown, and Postal checks on its own.

API or SMTP?

Use the API to get tags, scheduling, templates with variables and batch sending. If your system only speaks SMTP, use the free SMTP with the same key.

Send your first email through the API

Create the account, verify the domain and make your first POST on the Free plan.