01 · QUICKSTART
First email in three steps
send and status scopes.SENDPLUG_BASE_URL=https://sendplug.nirmaker.com. Accounts are free during the beta; the documented burst and daily sender limits apply.See the official Resend setup guides for Node.js and Python, then use the SendPlug base URL shown below.
npm install resend export SENDPLUG_BASE_URL="https://sendplug.nirmaker.com"
import { Resend } from "resend"; const resend = new Resend(process.env.SENDPLUG_API_TOKEN, { baseUrl: process.env.SENDPLUG_BASE_URL }); const { data, error } = await resend.emails.send({ from: "[email protected]", to: ["[email protected]"], subject: "Welcome", text: "Your account is ready." }); if (error) throw error; console.log(data.id);
pip install resend export RESEND_API_KEY="$SENDPLUG_API_TOKEN" export RESEND_API_URL="$SENDPLUG_BASE_URL"
import resend result = resend.Emails.send({ "from": "[email protected]", "to": ["[email protected]"], "subject": "Welcome", "text": "Your account is ready.", })
02 · RESEND SUBSET
Compatible where it counts
POST /emails returns { "id": "…" } for official SDK send calls. It accepts from, to, cc, bcc, subject, text, and html. At least one of text or html is required.
to is exactly one address. Address strings may include a display name, but SendPlug ignores the display name and uses the configured sender identity. cc and bcc allow up to 10 each. The from address must match the token-bound Gmail sender and never selects credentials.
03 · AUTHENTICATION
One token, one sender
Every request uses an API token in the HTTP Authorization header.
Authorization: Bearer $SENDPLUG_API_TOKEN
A token is bound to the Google sender selected when it was created. A token cannot send through another sender or read another sender's delivery records.
Scopes
| Scope | Allows |
|---|---|
send | Queue email through the token's selected sender. |
status | Read delivery status for email sent by that sender. |
04 · NATIVE API
Queue application email
POST /api/v1/send validates the request, selects the sender from the token, creates a status record, and returns immediately with HTTP 202 Accepted.
| Field | Type | Rules |
|---|---|---|
to REQUIRED | string[] | Exactly one valid email address. |
subject REQUIRED | string | 1–998 characters. |
body | string | Plain-text content. Recommended as a fallback when HTML is supplied. |
html | string | null | Optional HTML alternative. |
cc | string[] | null | Up to 10 valid email addresses. |
bcc | string[] | null | Up to 10 valid email addresses. |
sender_id | string | null | Omit when using an API token. If supplied, it must match the token's sender. |
Accepted response
{
"status": "queued",
"message_id": "5f…@sendplug",
"sender_id": "sender_…"
}202 response means the job was queued. It does not mean Gmail accepted or delivered the message. Poll the returned message_id.JavaScript example
const response = await fetch( `${process.env.SENDPLUG_BASE_URL}/api/v1/send`, { method: "POST", headers: { Authorization: `Bearer ${process.env.SENDPLUG_API_TOKEN}`, "Content-Type": "application/json" }, body: JSON.stringify({ to: ["[email protected]"], subject: "Welcome", body: "Your account is ready." }) } ); if (!response.ok) throw new Error(`Send failed: ${response.status}`); const queued = await response.json();
05 · STATUS
Read delivery state
Use the message_id from the send response. The token needs the status scope and must belong to the same sender.
curl "$SENDPLUG_BASE_URL/api/v1/emails/$MESSAGE_ID" \ -H "Authorization: Bearer $SENDPLUG_API_TOKEN"
queuedWaiting for a worker or retry.sendingReserved against quota and connecting to Gmail.sentAccepted by Gmail.failedStopped after a permanent or terminal error.{
"status": "sent",
"message_id": "5f…@sendplug",
"to": ["[email protected]"],
"subject": "Welcome",
"sender_id": "sender_…",
"created_at": "2026-07-23T10:00:00+00:00",
"updated_at": "2026-07-23T10:00:02+00:00",
"error": null,
"details": {
"recipients": ["[email protected]"],
"sender_id": "sender_…",
"subject": "Welcome",
"sent_at": "2026-07-23T10:00:02+00:00"
}
}06 · LIMITS
Safety before volume
The default sender safety limit is 400 recipients per UTC day. The administrator can configure another limit, while Gmail and Google Workspace enforce their own independent limits.
- Every
to,cc, andbccrecipient counts toward the sender's daily limit. - Quota is reserved atomically by the worker to prevent concurrent jobs from oversending.
- The default HTTP burst is 10 sends per API token per 60 seconds. A
429response includesRetry-After. This counter is process-local for the single-VM MVP. - A request can queue and later become
failedif no daily quota remains. Read the status record'serror. - Transient Gmail/network delivery failures retry automatically with backoff; permanent failures do not.
429 only after Retry-After. Do not automatically retry ambiguous timeouts or 5xx responses unless duplicate email is acceptable.Status records expire 7 days after their last status update. Persist any application-level audit information you need beyond that window.
07 · ERRORS
HTTP errors
| Status | Meaning | Action |
|---|---|---|
| 400 | The selected sender is unavailable or invalid. | Confirm the token's sender is still active. |
| 401 | The token is missing, malformed, invalid, or revoked. | Use a current token in the Bearer header. |
| 403 | The token lacks the required scope or requests another sender. | Grant the correct scope; omit sender_id. |
| 404 | The status does not exist, expired, or belongs to another sender. | Check the message ID and token sender. |
| 422 | The JSON body failed field validation. | Inspect the response's detail. |
| 429 | The per-token send burst was exceeded. | Wait for the Retry-After seconds before retrying. |
{ "detail": "Invalid or revoked API token" }08 · SECURITY
Production checklist
- Call SendPlug from your backend, server action, worker, or trusted function.
- Never embed API tokens in browser JavaScript, mobile binaries, URLs, or analytics events.
- Grant only the scopes each application needs.
- Rotate with overlap: create a new same-sender key, deploy it, verify
last_used_at, then revoke the old key. - App Passwords reach SendPlug over HTTPS and are encrypted before database storage; this is not end-to-end encryption.
- Do not send cold outreach or email people who did not request it.