How to Use the BillionMail Send API for Transactional Email (With curl and PHP)
Newsletters are only half of what most sites send. The other half is transactional email: password resets, order receipts, sign-up confirmations and login codes. These go to one person, right now, because they did something. BillionMail has a built-in Send API for exactly this, so your app or website can send through your own mail server instead of a paid service.
This guide shows how to create an API, call it with curl and PHP, and put personal values like a name or a code into the email.
Before you start
Step 1: Create the API
Open Send API in the left menu and click Create API. The form looks like this:
![[Image: attachment.php?aid=428]](https://adminsforum.com/attachment.php?aid=428)
Fill it in like this:
IP Whitelist is worth filling in: enter your app server's IP address (several are separated by commas). Then the key only works from that server, even if it leaks. Empty means any IP can use it.
After you save, the API appears in the list with its API Key, plus send count and open, click and bounce rates.
Step 2: Send a test with curl
The endpoint is on your BillionMail address (the same address and port you use for the dashboard). Run this from your app server:
A good answer has and . If you get a certificate error because you're testing with an IP or a self-signed certificate, fix the certificate rather than adding in production; see BillionMail SSL fixes.
Step 3: Put personal values in the email
Most transactional emails need something personal: a name, a reset link, a code. Send them in:
In the template, each value is written as , and so on. For example:
The names are case-sensitive: in the request means in the template, not .
Step 4: Call it from PHP
Keep the key in an environment variable or a config file outside the web root, never in JavaScript that runs in the browser.
Sending to several people
For a small list, use with instead of . For real newsletters, use a campaign instead; see send your first newsletter.
If it doesn't work
More BillionMail guides
Applies to BillionMail 4.9, October 2026. Replace and with your own domain and mail hostname. Menu names can change a little between versions.
Newsletters are only half of what most sites send. The other half is transactional email: password resets, order receipts, sign-up confirmations and login codes. These go to one person, right now, because they did something. BillionMail has a built-in Send API for exactly this, so your app or website can send through your own mail server instead of a paid service.
This guide shows how to create an API, call it with curl and PHP, and put personal values like a name or a code into the email.
Before you start
- BillionMail is installed and your domain's DNS is green. If not, start with installing BillionMail and the DNS setup guide.
- You have a template for the email. A simple HTML template is fine; see BillionMail email templates.
- Outgoing port 25 works on your server, or you use a relay. See how to check if port 25 is blocked.
Step 1: Create the API
Open Send API in the left menu and click Create API. The form looks like this:
Fill it in like this:
- API Name: something you'll recognise later, for example "Password reset".
- From: pick your domain and the mailbox it sends from, such as .Code:
- Display Name: the name people see in their inbox, like "Example Support".
- Subject and Email template: the subject line and the template to use.
- Status: on.
IP Whitelist is worth filling in: enter your app server's IP address (several are separated by commas). Then the key only works from that server, even if it leaks. Empty means any IP can use it.
After you save, the API appears in the list with its API Key, plus send count and open, click and bounce rates.
Step 2: Send a test with curl
The endpoint is
Code:
/api/batch_mail/api/sendCode:
curl -X POST 'https://mail.example.com/api/batch_mail/api/send' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"recipient":"[email protected]"}'Code:
"success":trueCode:
"code":0Code:
-kStep 3: Put personal values in the email
Most transactional emails need something personal: a name, a reset link, a code. Send them in
Code:
attribsCode:
{"recipient":"[email protected]",
"attribs":{"name":"Jane","code":"482913","link":"https://example.com/reset?t=abc"}}Code:
{{.API.name}}Code:
{{.API.code}}Code:
<p>Hi {{.API.name}},</p>
<p>Your login code is <b>{{.API.code}}</b>. It expires in 10 minutes.</p>Code:
codeCode:
{{.API.code}}Code:
{{.API.Code}}Step 4: Call it from PHP
Code:
<?php
function send_mail($to, array $vars) {
$ch = curl_init('https://mail.example.com/api/batch_mail/api/send');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('BM_API_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['recipient' => $to, 'attribs' => $vars]),
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
return !empty($res['success']);
}
send_mail('[email protected]', ['name' => 'Jane', 'code' => '482913']);Sending to several people
For a small list, use
Code:
/api/batch_mail/api/batch_sendCode:
"recipients":["[email protected]","[email protected]"]Code:
recipientIf it doesn't work
- 401 or "invalid key": check the header name is exactly and the API's status is on.Code:
X-API-Key
- Forbidden from your server: the IP Whitelist doesn't include the IP your app really uses. Check with on the app server.Code:
curl -4 ifconfig.me
- Success, but nothing arrives: the email is in the queue. See emails stuck in the send queue.
- Variables show up empty: the name in doesn't match the template exactly.Code:
attribs
More BillionMail guides
- WordPress email through BillionMail SMTP
- Import contacts, groups and tags
- Email templates explained
- SMTP relay with Amazon SES, Brevo or Mailgun
- Mailboxes and webmail
- Campaign analytics explained
- IP warm-up plan
- Move from Mailchimp or Sendy
- Add a second sending domain
- Send your first newsletter · DNS setup explained · Deliverability testing
Applies to BillionMail 4.9, October 2026. Replace
Code:
example.comCode:
mail.example.com
