Misar IO Docs

Send Email

Send transactional and marketing emails via POST /v1/send

Send Email

Base URL: https://api.misar.io/mail or https://api.misar.io/mail

Endpoint: POST /v1/send

Auth: Authorization: Bearer msk_...

Required scope: send, send:transactional, or send:marketing

Request

Headers

| Header | Required | Value | |--------|----------|-------| | Authorization | ✓ | Bearer msk_<your_key> | | Content-Type | ✓ | application/json | | X-Source-App | — | Your app name (used in logs) | | X-MisarMail-Sandbox | — | true to send in sandbox mode (not delivered) |

Body

{
  "from":    { "email": "[email protected]", "name": "My App" },
  "to":      [{ "email": "[email protected]", "name": "User Name" }],
  "subject": "Welcome to My App",
  "html":    "<h1>Hello!</h1><p>Welcome aboard.</p>",
  "text":    "Hello! Welcome aboard."
}

Fields

| Field | Type | Required | Notes | |-------|------|----------|-------| | from.email | string | ✓ | Must be a verified account owned by the API key | | from.name | string | — | Display name shown in email client | | to | Array<{email, name?}> | ✓ | Up to 100 recipients | | cc | Array<{email, name?}> | — | Up to 50 CC recipients | | bcc | Array<{email, name?}> | — | Up to 50 BCC recipients | | reply_to | {email, name?} | — | Reply-to address | | subject | string | ✓ | Max 998 characters | | html | string | ✓ (one of) | HTML email body | | text | string | ✓ (one of) | Plain text fallback — both recommended | | alias_id | UUID | — | Route via a specific SMTP pool | | idempotency_key | string | — | Prevent duplicate sends (max 128 chars) | | tags | string[] | — | Up to 10 tags for tracking | | metadata | Record<string, string> | — | Custom key-value data |

Either html or text is required — both are strongly recommended. Many email clients render only plain text.

Responses

200 — Sent

{
  "success":    true,
  "message_id": "msg_abc123",
  "provider":   "smtp",
  "timestamp":  "2026-02-17T12:00:00.000Z"
}

202 — Queued for Retry

{
  "success": false,
  "queued":  true,
  "message": "Email queued for retry"
}

The primary SMTP provider was unavailable. The email is automatically retried — no action needed. Do not treat 202 as an error.

422 — Suppressed

{
  "success":    false,
  "suppressed": true,
  "error":      "Send suppressed — recipient unsubscribed or bounced"
}

The recipient is on your suppression list (previously unsubscribed or hard-bounced). The send was intentionally blocked to protect your deliverability. Do not retry — remove the recipient from your send list or check their status via the Contacts API.

Sandbox Mode

Append the X-MisarMail-Sandbox: true header to store the send in the sandbox_sends table without delivering to the real recipient. Useful for integration testing and CI pipelines.

curl https://api.misar.io/mail/v1/send \
  -H "Authorization: Bearer msk_your_key_here" \
  -H "Content-Type: application/json" \
  -H "X-MisarMail-Sandbox: true" \
  -d '{
    "from":    { "email": "[email protected]", "name": "Misar" },
    "to":      [{ "email": "[email protected]" }],
    "subject": "Sandbox test",
    "text":    "This will not be delivered."
  }'

Sandbox response:

{
  "success":    true,
  "message_id": "sandbox_msg_xyz789",
  "provider":   "sandbox",
  "timestamp":  "2026-02-17T12:00:00.000Z"
}

Requires the sandbox scope on your API key. Sandbox sends count against rate limits but not against your monthly plan quota.

Examples

curl https://api.misar.io/mail/v1/send \
  -H "Authorization: Bearer msk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "from":    { "email": "[email protected]", "name": "Misar" },
    "to":      [{ "email": "[email protected]", "name": "User" }],
    "subject": "Welcome to Misar!",
    "html":    "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
    "text":    "Welcome! Thanks for signing up."
  }'
const res = await fetch("https://api.misar.io/mail/v1/send", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.MISARMAIL_API_KEY}`,
    "Content-Type": "application/json",
    "X-Source-App": "MyApp",
  },
  body: JSON.stringify({
    from:    { email: "[email protected]", name: "Misar" },
    to:      [{ email: "[email protected]", name: "User" }],
    subject: "Welcome to Misar!",
    html:    "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
    text:    "Welcome! Thanks for signing up.",
    idempotency_key: `welcome-${userId}`,
  }),
});

const data = await res.json();

if (!res.ok && !data.queued) {
  throw new Error(data.error || "Failed to send email");
}
import os, requests

response = requests.post(
    "https://api.misar.io/mail/v1/send",
    headers={
        "Authorization": f"Bearer {os.environ['MISARMAIL_API_KEY']}",
        "Content-Type": "application/json",
        "X-Source-App": "MyApp",
    },
    json={
        "from":    {"email": "[email protected]", "name": "Misar"},
        "to":      [{"email": "[email protected]", "name": "User"}],
        "subject": "Welcome to Misar!",
        "html":    "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
        "text":    "Welcome! Thanks for signing up.",
        "idempotency_key": f"welcome-{user_id}",
    },
)

data = response.json()
if not response.ok and not data.get("queued"):
    raise Exception(data.get("error", "Failed to send email"))

Idempotency

Use idempotency_key to prevent duplicate emails when retrying failed requests:

{
  "idempotency_key": "welcome-usr_abc123"
}

If a request with the same key was already delivered within 24 hours, the API returns the original result without re-sending:

{
  "success":    true,
  "message_id": "msg_abc123",
  "provider":   "smtp",
  "idempotent": true,
  "timestamp":  "2026-02-17T12:00:00.000Z"
}

Use a unique key per logical send event (e.g., welcome-<userId>, invoice-<invoiceId>).

SMTP Pool Routing

By default, emails are routed through the best available SMTP pool. To force a specific pool (e.g., transactional vs. promotional), pass alias_id:

{
  "alias_id": "550e8400-e29b-41d4-a716-446655440000"
}

Find alias IDs in Settings → SMTP Pools or via the API Keys settings page.