Bulk Send
The Bulk Send API lets you queue a marketing campaign (subject, body, and a recipient list of up to 50,000 addresses) in one request. All bulk jobs are treated as marketing emails: unsubscribed recipients are skipped automatically and List-Unsubscribe headers are injected. The system delivers in the background at a controlled rate, handling suppression, quota deduction, and DKIM signing automatically.
You can also create and track campaigns from the Bulk Send page in the dashboard.
Create a bulk job
/v1/user/email/bulk| Field | Type | Required | Notes |
|---|---|---|---|
fromEmail | string | Yes | Must use a verified sender domain |
fromName | string | No | Defaults to account business name → first name → email local part |
subject | string | Yes | Max 998 characters |
bodyHtml | string | No* | Required if bodyText is omitted. Omit to use your configured email template. |
bodyText | string | No* | Required if bodyHtml is omitted |
recipients | string[] | Yes | Array of email strings, 1–50,000. Duplicates are deduplicated. |
Response 202: { jobId, totalCount, status: "pending" }
Code example
curl -X POST https://api.altermail-console.com.ng/v1/user/email/bulk \
-H "Content-Type: application/json" \
-H "token: YOUR_API_KEY" \
-d '{
"fromEmail": "campaigns@yourdomain.com",
"fromName": "Your Company",
"subject": "October product update",
"bodyHtml": "<h1>What'\''s new</h1><p>Here'\''s what shipped this month.</p>",
"bodyText": "What'\''s new: here'\''s what shipped this month.",
"recipients": ["one@example.com", "two@example.com", "three@example.com"]
}'const response = await fetch("https://api.altermail-console.com.ng/v1/user/email/bulk", {
method: "POST",
headers: {
"Content-Type": "application/json",
"token": "YOUR_API_KEY",
},
body: JSON.stringify({
fromEmail: "campaigns@yourdomain.com",
fromName: "Your Company",
subject: "October product update",
bodyHtml: "<h1>What's new</h1><p>Here's what shipped this month.</p>",
bodyText: "What's new: here's what shipped this month.",
recipients: ["one@example.com", "two@example.com", "three@example.com"],
}),
});
const job = await response.json();
console.log(job);
// { jobId: "uuid", totalCount: 3, status: "pending" }
// Poll for status:
const statusRes = await fetch(`https://api.altermail-console.com.ng/v1/user/email/bulk/${job.jobId}`, {
headers: { "token": "YOUR_API_KEY" },
});
console.log(await statusRes.json());import requests
res = requests.post(
"https://api.altermail-console.com.ng/v1/user/email/bulk",
headers={
"Content-Type": "application/json",
"token": "YOUR_API_KEY",
},
json={
"fromEmail": "campaigns@yourdomain.com",
"fromName": "Your Company",
"subject": "October product update",
"bodyHtml": "<h1>What's new</h1><p>Here's what shipped this month.</p>",
"bodyText": "What's new: here's what shipped this month.",
"recipients": ["one@example.com", "two@example.com", "three@example.com"],
},
)
job = res.json()
print(job)
# { "jobId": "uuid", "totalCount": 3, "status": "pending" }<?php
$payload = json_encode([
"fromEmail" => "campaigns@yourdomain.com",
"fromName" => "Your Company",
"subject" => "October product update",
"bodyHtml" => "<h1>What's new</h1><p>Here's what shipped this month.</p>",
"bodyText" => "What's new: here's what shipped this month.",
"recipients" => ["one@example.com", "two@example.com", "three@example.com"],
]);
$ch = curl_init("https://api.altermail-console.com.ng/v1/user/email/bulk");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"token: YOUR_API_KEY",
],
]);
$job = json_decode(curl_exec($ch), true);
curl_close($ch);
var_dump($job); // ["jobId" => "uuid", "totalCount" => 3, "status" => "pending"]package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"fromEmail": "campaigns@yourdomain.com",
"fromName": "Your Company",
"subject": "October product update",
"bodyHtml": "<h1>What's new</h1><p>Here's what shipped this month.</p>",
"bodyText": "What's new: here's what shipped this month.",
"recipients": []string{"one@example.com", "two@example.com", "three@example.com"},
})
req, _ := http.NewRequest("POST", "https://api.altermail-console.com.ng/v1/user/email/bulk", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("token", "YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(out))
}using System.Net.Http;
using System.Net.Http.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("token", "YOUR_API_KEY");
var payload = new {
fromEmail = "campaigns@yourdomain.com",
fromName = "Your Company",
subject = "October product update",
bodyHtml = "<h1>What's new</h1><p>Here's what shipped this month.</p>",
bodyText = "What's new: here's what shipped this month.",
recipients = new[] { "one@example.com", "two@example.com", "three@example.com" },
};
var response = await client.PostAsJsonAsync("https://api.altermail-console.com.ng/v1/user/email/bulk", payload);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine((int)response.StatusCode + " " + result);import java.net.http.*;
import java.net.URI;
var body = """
{
"fromEmail": "campaigns@yourdomain.com",
"fromName": "Your Company",
"subject": "October product update",
"bodyHtml": "<h1>What's new</h1><p>Here's what shipped this month.</p>",
"bodyText": "What's new: here's what shipped this month.",
"recipients": ["one@example.com", "two@example.com", "three@example.com"]
}
""";
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.altermail-console.com.ng/v1/user/email/bulk"))
.header("Content-Type", "application/json")
.header("token", "YOUR_API_KEY")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
var response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());#include <curl/curl.h>
#include <string>
int main() {
CURL* curl = curl_easy_init();
if (!curl) return 1;
const std::string payload = R"({
"fromEmail": "campaigns@yourdomain.com",
"fromName": "Your Company",
"subject": "October product update",
"bodyHtml": "<h1>What's new</h1><p>Here's what shipped this month.</p>",
"bodyText": "What's new: here's what shipped this month.",
"recipients": ["one@example.com", "two@example.com", "three@example.com"]
})";
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "token: YOUR_API_KEY");
curl_easy_setopt(curl, CURLOPT_URL, "https://api.altermail-console.com.ng/v1/user/email/bulk");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str());
curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return 0;
}
// Compile: g++ -o bulk_send bulk_send.cpp -lcurlCheck job status
/v1/user/email/bulk/:jobId{
"jobId": "uuid",
"status": "pending | processing | completed | paused_quota",
"totalCount": 4000,
"sentCount": 1800,
"suppressedCount": 42,
"failedCount": 3,
"remainingCount": 2155,
"createdAt": "...",
"startedAt": "...",
"completedAt": null
}List recent jobs
/v1/user/email/bulkReturns the 20 most recent jobs for the authenticated account, sorted newest first.
Job status values
| Status | Meaning |
|---|---|
pending | Job created, waiting for the worker to start |
processing | Worker is actively sending recipients |
completed | All recipients processed |
paused_quota | Quota exhausted mid-job: resumes automatically after billing is topped up |
Bulk send checks quota per-recipient, not atomically
Unlike a single send with CC/BCC (which checks its whole recipient count in one atomic operation), a bulk job's worker checks quota one recipient at a time. If your monthly quota and PAYG credits run out partway through a job, recipients already processed stay sent, and the job pauses at paused_quota instead of failing outright, and resumes automatically once more quota becomes available. See Quota & Billing for the single-send comparison.