Mailman Engine API

Mailman is a high-performance transactional email gateway written in Go. It abstracts upstream delivery providers (Resend, Brevo, SendGrid, Amazon SES, and native SMTP) behind a unified, resilient HTTP REST interface.

Mailman eliminates cross-origin resource sharing (CORS) barriers, provides automated background queuing with exponential backoff retries, tracks link clicks and opens, and exposes function calling schemas for autonomous AI agents.

Quickstart

Send your first email using cURL in seconds.

Dispatch a request to POST https://mailman.cloudrails.in/api/v1/send with your credentials:

curl -X POST https://mailman.cloudrails.in/api/v1/send \
  -H "Content-Type: application/json" \
  -H "x-api-access-code: YOUR_ACCESS_CODE" \
  -H "x-api-secret-key: YOUR_SECRET_KEY" \
  -d '{
    "to": "recipient@example.com",
    "replyTo": "support@yourdomain.com",
    "subject": "Hello from Mailman",
    "html": "<p>This is a transactional message sent via Mailman Engine.</p>",
    "trackOpens": true,
    "trackClicks": true
  }'

Authentication & Access Codes

Authenticate API dispatch requests via two required HTTP headers.

Every programmatic dispatch request must provide both credentials in the request headers:

Header Format Description
x-api-access-code name@mailman The public routing identifier for your API key (e.g. vtx@mailman).
x-api-secret-key sk_live_... The confidential private secret generated when the API key is issued. Never commit this key to version control.

CORS Resilience & Universal Connectivity

Engineered to connect with any framework, client, or serverless runtime.

Unlike traditional mail proxies that block browser-based or cross-domain fetch calls, Mailman provides complete preflight support:

  • Preflight OPTIONS Support: All preflight requests return 204 No Content with cached permissions for 24 hours (Access-Control-Max-Age: 86400).
  • Dynamic Origin Reflection: Automatically reflects the caller's origin for web applications, SPAs, and mobile WebViews.
  • Allowed Headers: Explicitly allows Content-Type, Authorization, x-api-access-code, x-api-secret-key, Accept, Origin, X-Requested-With, Cache-Control.
  • Connectable Everywhere: Seamlessly integrate from browser client-side code, Next.js server actions, Cloudflare Workers, Supabase Edge Functions, Node.js, Python, or automation platforms (n8n, Make, Zapier).

Email Dispatch API

POST https://mailman.cloudrails.in/api/v1/send

Request Body Parameters

Field Type Required Description
to string Required Recipient email address.
subject string Required Subject line of the email.
html string Optional HTML body. Links are rewritten through the tracking gateway when trackClicks is enabled.
text string Optional Plaintext fallback content.
recipientName string Optional Display name for recipient.
replyTo string Optional Custom Reply-To email address (e.g. support@yourdomain.com). If omitted, automatically inherits the server's configured default Reply-To.
queue boolean Optional Dispatches asynchronously through the background worker queue with exponential backoff retries (defaults to true).
trackOpens boolean Optional Injects a transparent 1x1 tracking pixel to record email opens. Default false.
trackClicks boolean Optional Rewrites links for real-time click telemetry. Default false.
variables object Optional Key-value dictionary of placeholders replaced inside subject and HTML (e.g. {{name}}).
attachments array Optional Array of file attachments (PDFs, invoices, images). Each item accepts filename, contentType (e.g. application/pdf), and base64-encoded content.
fromEmail string Optional Custom sender email address override (e.g. team@yourdomain.com). Defaults to the connected mail server's verified From address.
fromName string Optional Custom sender display name (e.g. Acme Notifications).
templateId string Optional Server-side stored template identifier (e.g. tpl_auth_code, tpl_letter). Automatically populates HTML and subject with template contents and merges provided variables.
idempotencyKey string Optional Unique client key to prevent duplicate sends on network retries. Can also be passed via the Idempotency-Key HTTP header.
sandbox boolean Optional Sandbox / Dry-run simulation mode. Renders variables and templates, checks authentication, logs the transaction, but skips the external network dispatch. Can also be enabled via x-mailman-sandbox: true header.
webhookUrl string Optional HTTPS callback endpoint to receive asynchronous event notifications when the message is delivered, fails/bounces, is opened, or has links clicked.
mailServerId string Optional Explicitly override the upstream mail server, or specify "round_robin" to orchestrate and balance across all active servers with remaining capacity.

Response Schemas

HTTP 200 OK — Direct Immediate Dispatch
{
  "success": true,
  "status": "sent",
  "messageId": "msg_api_vtx_core_1790501913118477680",
  "mailServer": "Primary Resend"
}
HTTP 202 Accepted — Background Queue
{
  "success": true,
  "status": "queued",
  "queueId": "q_1790501907577260795_api_vtx_core",
  "messageId": "msg_api_vtx_core_1790501907577227391",
  "mailServer": "Primary Resend"
}

Error Codes

Code Meaning Resolution
401 Unauthorized Missing or invalid headers. Verify x-api-access-code and x-api-secret-key match an active API key.
429 Too Many Requests Daily limit quota reached. Adjust the daily quota in the Manage API view or enable queue: true.
502 Bad Gateway Upstream provider rejected dispatch. Check the provider API key or SMTP credentials configured on the assigned server in the Servers tab.

Delivery Status & Message Polling

Poll the real-time status, opens, clicks, or error report of any dispatched email using its messageId or id.

GET https://mailman.cloudrails.in/api/v1/messages/{id}
curl -X GET "https://mailman.cloudrails.in/api/v1/messages/msg_api_live_1790501907577227391" \
  -H "x-api-access-code: vtx@mailman" \
  -H "x-api-secret-key: sk_live_..."
{
  "success": true,
  "messageId": "msg_api_live_1790501907577227391",
  "status": "sent",              // "sent" | "queued" | "failed" | "sandbox"
  "recipient": "user@example.com",
  "sender": "team@example.com",
  "subject": "Your verification code",
  "mailServer": "Primary Resend",
  "provider": "resend",
  "idempotencyKey": "req_849201",
  "opens": 1,
  "clicks": 0,
  "error": "",
  "timestamp": "2026-10-02T12:00:00Z"
}

Delivery, Bounce & Engagement Webhooks

When you specify webhookUrl in your dispatch payload, Mailman automatically posts JSON event payloads to your server as soon as the email status updates.

Webhook Event Payload (POST to your endpoint)
{
  "event": "email.sent",         // "email.sent" | "email.failed" | "email.sandbox" | "email.opened" | "email.clicked"
  "messageId": "msg_api_live_1790501907577227391",
  "recipient": "user@example.com",
  "subject": "Your verification code",
  "status": "sent",
  "mailServer": "Primary Resend",
  "timestamp": "2026-10-02T12:00:01Z",
  "error": ""                    // Populated with bounce/rejection message if event is "email.failed"
}

Bulk / Batch Dispatch API

Dispatch up to 1,000 personalized emails in a single request with high-speed parallel worker execution.

POST https://mailman.cloudrails.in/api/v1/send/bulk
curl -X POST https://mailman.cloudrails.in/api/v1/send/bulk \
  -H "Content-Type: application/json" \
  -H "x-api-access-code: vtx@mailman" \
  -H "x-api-secret-key: sk_live_..." \
  -d '{
    "concurrency": 20,
    "messages": [
      {
        "to": "alex@example.com",
        "templateId": "tpl_auth_code",
        "variables": { "code": "482019" }
      },
      {
        "to": "sarah@example.com",
        "templateId": "tpl_letter",
        "variables": { "name": "Sarah", "company": "Acme Inc" }
      }
    ]
  }'

Background Queue & Retries

Asynchronous worker pool with exponential backoff.

When sending transactional or bulk notifications, Mailman automatically enqueues emails into an asynchronous worker pool (returning an instant 202 Accepted) so your API callers are never blocked by slow network sockets or remote mail server latency.

If an upstream service encounters a temporary timeout or rate limit, the worker retains the item in the pending state and automatically retries with exponential backoff (up to 3 attempts). Track queue activity in real-time in the Queue view within the console.

PDF & File Attachments API

Send invoices, reports, PDFs, and documents natively across all mail providers.

Mailman has full support for PDF attachments over the REST API. Attachments are passed in the attachments array encoded as standard Base64. Mailman automatically formats and transmits them using the correct MIME headers and provider specs (Resend, Brevo, SendGrid, Postmark, and native SMTP):

curl -X POST https://mailman.cloudrails.in/api/v1/send \
  -H "Content-Type: application/json" \
  -H "x-api-access-code: YOUR_ACCESS_CODE" \
  -H "x-api-secret-key: YOUR_SECRET_KEY" \
  -d '{
    "to": "client@example.com",
    "subject": "Your Monthly Invoice (PDF)",
    "html": "<p>Please find your PDF invoice attached.</p>",
    "replyTo": "billing@yourdomain.com",
    "attachments": [
      {
        "filename": "invoice-2026.pdf",
        "contentType": "application/pdf",
        "content": "JVBERi0xLjQKJcTl8uXrp/Og0MTGCjQgMCBvYmoK..."
      }
    ]
  }'

AI Agent Function Calling

Equip autonomous LLM agents (OpenAI, Anthropic Claude, Google Gemini) to dispatch emails safely.

OpenAI Function Tool Schema

Provide this definition in your agent's tools array:

{
  "type": "function",
  "function": {
    "name": "send_transactional_email",
    "description": "Dispatches a transactional email through Mailman Engine gateway.",
    "parameters": {
      "type": "object",
      "properties": {
        "to": {
          "type": "string",
          "description": "Recipient email address."
        },
        "subject": {
          "type": "string",
          "description": "Concise and professional subject line."
        },
        "html": {
          "type": "string",
          "description": "Semantic HTML formatted body. Do not output markdown."
        },
        "replyTo": {
          "type": "string",
          "description": "Optional custom Reply-To email address (e.g. support@company.com)."
        },
        "trackOpens": {
          "type": "boolean",
          "description": "Whether to inject open tracking pixel."
        },
        "trackClicks": {
          "type": "boolean",
          "description": "Whether to track link clicks."
        },
        "queue": {
          "type": "boolean",
          "description": "Whether to deliver asynchronously via background queue."
        }
      },
      "required": ["to", "subject", "html"]
    }
  }
}

Anthropic Claude Tool Specification

{
  "name": "send_transactional_email",
  "description": "Sends transactional email via Mailman Engine gateway.",
  "input_schema": {
    "type": "object",
    "properties": {
      "to": { "type": "string", "description": "Destination email address." },
      "subject": { "type": "string", "description": "Subject line." },
      "html": { "type": "string", "description": "HTML content of the email." },
      "replyTo": { "type": "string", "description": "Optional custom Reply-To email address." }
    },
    "required": ["to", "subject", "html"]
  }
}

Recommended Agent System Prompt

You have access to the `send_transactional_email` tool connected to Mailman Engine.

1. RECIPIENT & SUBJECT: Always confirm the recipient address. Generate a clear subject without spam trigger words.

2. HTML BODY: Output clean semantic HTML (<p>, <h2>, <strong>, <ul>, <li>, <a href="...">). Never output raw markdown.

3. STATUS HANDLING: HTTP 200 means dispatched immediately. HTTP 202 means queued for delivery.

SDKs & Code Examples

Standard implementation patterns for major programming languages.

TypeScript / Next.js (Server Action or Route Handler)
import axios from 'axios';

export async function sendEmailNotification(to: string, subject: string, html: string) {
  const response = await axios.post(
    'https://mailman.cloudrails.in/api/v1/send',
    {
      to,
      subject,
      html,
      replyTo: 'support@yourdomain.com',
      trackOpens: true,
      trackClicks: true,
      queue: true
    },
    {
      headers: {
        'Content-Type': 'application/json',
        'x-api-access-code': process.env.MAILMAN_ACCESS_CODE!,
        'x-api-secret-key': process.env.MAILMAN_SECRET_KEY!
      }
    }
  );

  return response.data;
}
Python (Requests)
import os
import requests

def dispatch_email(recipient: str, subject: str, html_body: str, reply_to: str = None):
    url = "https://mailman.cloudrails.in/api/v1/send"
    headers = {
        "Content-Type": "application/json",
        "x-api-access-code": os.environ["MAILMAN_ACCESS_CODE"],
        "x-api-secret-key": os.environ["MAILMAN_SECRET_KEY"]
    }
    payload = {
        "to": recipient,
        "subject": subject,
        "html": html_body,
        "replyTo": reply_to or "support@yourdomain.com",
        "trackOpens": True,
        "trackClicks": True
    }
    
    res = requests.post(url, json=payload, headers=headers, timeout=15)
    res.raise_for_status()
    return res.json()
Go (net/http)
package mailman

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

type DispatchPayload struct {
	To          string `json:"to"`
	Subject     string `json:"subject"`
	HTML        string `json:"html"`
	TrackOpens  bool   `json:"trackOpens"`
	TrackClicks bool   `json:"trackClicks"`
}

func SendEmail(to, subject, html string) error {
	payload := DispatchPayload{
		To:          to,
		Subject:     subject,
		HTML:        html,
		TrackOpens:  true,
		TrackClicks: true,
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", "https://mailman.cloudrails.in/api/v1/send", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("x-api-access-code", os.Getenv("MAILMAN_ACCESS_CODE"))
	req.Header.Set("x-api-secret-key", os.Getenv("MAILMAN_SECRET_KEY"))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
		return fmt.Errorf("dispatch returned status %d", resp.StatusCode)
	}
	return nil
}