Skip to content

Send transactional email (API)

Send transactional email (API)

Standard examples in cURL, Node.js, Python, PHP, and Ruby for POST /api/email.

Use the transactional API for app-triggered messages (password resets, receipts, alerts). This is not for bulk campaigns — those use Marketing domains and the campaign/automation UI.

Before you send

  1. Verify a transactional domain (example: acme.com).
  2. Complete account approval (Settings → Request Approval). Wait until status is approved.
  3. Create a token under Account → API Tokens.
  4. Send from an address on that verified domain (example: noreply@acme.com).

Marketing-only domains will be rejected. Live sends on this endpoint require the same account approval as campaigns and automations.

Endpoint

POST https://mailivate.com/api/email
Header Value
Authorization Bearer {your-api-token}
Accept application/json
Content-Type application/json

Request body

Postmark-style field names and Mailivate aliases both work.

Field Aliases Required Description
From from Yes Name <email@verified-domain> or bare email on a transactional verified domain
To to Yes One address, or comma-separated list
Subject subject Yes Subject line
HtmlBody html, html_body Yes* HTML body
TextBody text, plain_body No Plain text; used to build HTML if HtmlBody is omitted
Cc cc No Carbon copy recipients
Bcc bcc No Blind carbon copy recipients
ReplyTo reply_to No Reply-To address
store No Defaults to true; set false to skip storing the send in the transactional log

* Provide HtmlBody/html, or provide TextBody/text so Mailivate can derive HTML.

Example JSON

{
  "From": "Acme App <noreply@acme.com>",
  "To": "jane@example.com",
  "Subject": "Your password reset link",
  "HtmlBody": "<p>Click <a href=\"https://acme.com/reset\">here</a> to reset your password.</p>",
  "TextBody": "Open https://acme.com/reset to reset your password."
}

Success response

{
  "MessageID": "…",
  "SubmittedAt": "2026-08-14T01:00:00+00:00",
  "To": "jane@example.com",
  "ErrorCode": 0,
  "Message": "OK"
}

Standard examples

Replace the token and From domain with your values. Base URL for hosted Mailivate is always https://mailivate.com.

cURL

export MAILIVATE_URL="https://mailivate.com"
export MAILIVATE_TOKEN="your-api-token"

curl -sS -X POST "${MAILIVATE_URL}/api/email" \
  -H "Authorization: Bearer ${MAILIVATE_TOKEN}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "From": "Acme App <noreply@acme.com>",
    "To": "jane@example.com",
    "Subject": "Your password reset link",
    "HtmlBody": "<p>Click <a href=\"https://acme.com/reset\">here</a> to reset your password.</p>"
  }'

Node.js

const MAILIVATE_URL = process.env.MAILIVATE_URL ?? 'https://mailivate.com';
const MAILIVATE_TOKEN = process.env.MAILIVATE_TOKEN;

const response = await fetch(`${MAILIVATE_URL}/api/email`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${MAILIVATE_TOKEN}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    From: 'Acme App <noreply@acme.com>',
    To: 'jane@example.com',
    Subject: 'Your password reset link',
    HtmlBody:
      '<p>Click <a href="https://acme.com/reset">here</a> to reset your password.</p>',
  }),
});

if (!response.ok) {
  throw new Error(`Mailivate error ${response.status}: ${await response.text()}`);
}

const result = await response.json();
console.log(result.MessageID);

Python

import os
import requests

MAILIVATE_URL = os.environ.get("MAILIVATE_URL", "https://mailivate.com")
MAILIVATE_TOKEN = os.environ["MAILIVATE_TOKEN"]

response = requests.post(
    f"{MAILIVATE_URL}/api/email",
    headers={
        "Authorization": f"Bearer {MAILIVATE_TOKEN}",
        "Accept": "application/json",
        "Content-Type": "application/json",
    },
    json={
        "From": "Acme App <noreply@acme.com>",
        "To": "jane@example.com",
        "Subject": "Your password reset link",
        "HtmlBody": '<p>Click <a href="https://acme.com/reset">here</a> to reset your password.</p>',
    },
    timeout=30,
)
response.raise_for_status()
print(response.json()["MessageID"])

PHP

<?php

$token = getenv('MAILIVATE_TOKEN');
$url = rtrim(getenv('MAILIVATE_URL') ?: 'https://mailivate.com', '/').'/api/email';

$payload = [
    'From' => 'Acme App <noreply@acme.com>',
    'To' => 'jane@example.com',
    'Subject' => 'Your password reset link',
    'HtmlBody' => '<p>Click <a href="https://acme.com/reset">here</a> to reset your password.</p>',
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer '.$token,
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_RETURNTRANSFER => true,
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException("Mailivate error {$status}: {$body}");
}

$result = json_decode($body, true);
echo $result['MessageID'];

Ruby

require "json"
require "net/http"
require "uri"

mailivate_url = ENV.fetch("MAILIVATE_URL", "https://mailivate.com")
token = ENV.fetch("MAILIVATE_TOKEN")

uri = URI.join(mailivate_url, "/api/email")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{token}"
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request.body = {
  From: "Acme App <noreply@acme.com>",
  To: "jane@example.com",
  Subject: "Your password reset link",
  HtmlBody: '<p>Click <a href="https://acme.com/reset">here</a> to reset your password.</p>'
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

raise "Mailivate error #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)

puts JSON.parse(response.body)["MessageID"]

Template sends

To send a saved transactional template by name, use:

POST https://mailivate.com/api/transactional-mails/send
curl -sS -X POST "${MAILIVATE_URL}/api/transactional-mails/send" \
  -H "Authorization: Bearer ${MAILIVATE_TOKEN}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "mail_name": "order-receipt",
    "from": "Store <orders@acme.com>",
    "to": "jane@example.com",
    "replacements": {
      "order_number": "ORD-12345",
      "total": "$99.00"
    }
  }'

See Transactional templates for creating named templates in the UI.

Common errors

Status / message Cause Fix
401 Missing or invalid token Create/copy a token under Account → API Tokens
422 on from / From Domain not verified for transactional use Verify under Transactional domains; do not use a marketing-only subdomain
406 Account not approved, or recipient suppressed Complete account approval, or check Settings → Suppressions
Empty body / network error Wrong host or blocked egress Call https://mailivate.com from your backend, never from browser JavaScript

Security

  • Store MAILIVATE_TOKEN in server environment variables or a secrets manager.
  • Call the API only from your backend.
  • Rotate and revoke unused tokens regularly.

See also

Confirm