A small API surface.
A complete message record.
POSTA sends product email through Azure Communication Services while keeping projects, domain identity, quota, suppressions, provider events, webhook attempts, and inbound conversations in one operational surface.
Never expose a pa_… key in browser JavaScript, a mobile binary, a public repository, or client-visible logs.
Send an email
Create an API key, verify the domain used in the From address, install the SDK, and make the request from your server.
import { Posta } from "@esaart/posta";
const posta = new Posta(process.env.POSTA_API_KEY);
const message = await posta.emails.send({
from: "Product <hello@mail.acme.dev>",
to: "maya@example.net",
subject: "Your workspace is ready",
html: "<strong>Welcome to Acme.</strong>",
idempotencyKey: "welcome/user_482"
});Use one bearer token.
Authenticate every public API request with a project API key. Sending keys can send; full keys can also read message history. A key may additionally be restricted to one sending domain.
Authorization: Bearer pa_••••••••One endpoint,
three content paths.
Send inline HTML, plain text, or a stored template. from and to are always required; subject is required unless the template supplies one.
fromrequiredName and address on a verified project domain.
torequiredOne address or an array of up to 50 recipients.
html / textcontentProvide either format, both formats, or a template.
templatecontentStored template ID or slug; variables fill {{tokens}}.
reply_tooptionalAddress that receives recipient replies.
attachmentsoptionalUp to 10 direct uploads (25 MB each / 100 MB total) or 2.5 MB inline base64.
Send up to 100
message objects.
POST /api/v1/emails/batch accepts a bare array or an { emails: […] } object. The entire batch may contain at most 100 recipients, and each result independently contains an ID or an error.
POST /api/v1/emails/batchAccept now.
Dispatch later.
Set send_at to a future ISO 8601 timestamp. The Node SDK field is scheduledAt. Attachments uploaded with posta.attachments.upload remain available to scheduled sends without placing binary data in the scheduler record.
send_at: "2026-08-20T09:00:00Z"Version content.
Send by slug.
Pass a template ID or slug and a string-to-string variables object. Variables interpolate into the stored subject and HTML; a request subject overrides the template subject.
{
"from": "hello@mail.acme.dev",
"to": "maya@example.net",
"template": "workspace-ready",
"variables": { "name": "Maya" }
}Retries without
duplicate sends.
Supply a stable Idempotency-Key for the logical product action. Repeating it returns the saved response with Idempotent-Replay: true instead of sending again.
Idempotency-Key: order_482_receiptSubscribe to durable events.
POSTA signs the raw body with HMAC-SHA256 in Posta-Signature. Failed attempts are retried after 1 minute, 5 minutes, 30 minutes, and 2 hours — five attempts total — with history visible in the dashboard.
email.sentoutbound02email.deliveredoutbound03email.openedoutbound04email.clickedoutbound05email.bouncedoutbound06email.complainedoutbound07email.receivedinboundTurn replies into
application data.
After an inbound provider and MX route are configured, POSTA stores messages as hosted conversations and emits a normalized email.received webhook with text, HTML, headers, and attachment metadata. Your application consumes that signed event; it does not call the provider-ingestion route directly.
Verify identity
before sending.
Add a domain in the dashboard and publish the exact ownership, SPF, DKIM selectors, and DMARC guidance POSTA returns from Azure ACS. A domain-scoped key cannot send from any other domain.
Copy them from Dashboard → Domains. Do not reuse sample records from documentation.
Catch obvious risk
before a send.
POST /api/v1/validate checks syntax, likely provider typos, disposable domains, role addresses, and MX availability. It accepts one email or up to 100 emails. This is a hygiene signal, not proof that a mailbox exists.
Useful failures,
one response shape.
Errors return { "error": { "message": "…" } }. Fix 400/401/402/403/422 responses before retrying. For 429, respect Retry-After. Retry transient 5xx responses with backoff and an idempotency key.
401HTTPInvalid or missing API key.
402HTTPMonthly plan quota reached.
403HTTPPermission, domain scope, or project pause.
422HTTPInvalid content, limits, template, or recipients.
429HTTPPer-minute or daily rate limit.
502 / 503HTTPProvider or required infrastructure unavailable.
Explicit boundaries.
Single sends allow 50 recipients, 500 subject characters, approximately 1 MB of HTML plus text, and 10 direct-upload attachments up to 25 MB each / 100 MB total. Up to 7 MB raw is delivered as MIME; larger selections use private seven-day links. Legacy base64 requests retain a 2.5 MB total limit. Batch requests allow 100 items and 100 total recipients. Validation accepts 100 addresses.
Use the interface
that fits the job.
The implemented clients are the zero-dependency Node/TypeScript package @esaart/posta, the Python distribution esaart-posta, and the Node 18+ CLI @esaart/posta-cli.
npm i @esaart/postaNode / TypeScriptTyped sends, batch, validation, listing, attachments, and signature verification.
pip install esaart-postaPython 3.8+Send, batch, validation, listing, attachments, and signature verification.
npm i -g @esaart/posta-cliCLISend, batch, validate, and list from a terminal.
Documentation
for AI tools.
/llms.txt is the concise index. /llms-full.txt contains the complete integration context suitable for coding agents and answer engines.