Airmail

Developer API

Choose a framework guide or use standard HTTP and authenticated SMTP. No Airmail-specific SDK is required.

Integration and migration guides

REST quickstart

Set AIRMAIL_API_KEY in your server environment and replace the example addresses. Production approval is required; before approval use the dashboard's controlled first-send step. Save the accepted msg_* ID and reuse one stable Idempotency-Key for retries of the same logical message.

cURL

curl --connect-timeout 10 --max-time 20 --fail-with-body https://api.airmailai.tech/v1/messages \
  -H 'Authorization: Bearer '"$AIRMAIL_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: account-481-welcome' \
  --data '{
  "from": {
    "email": "notifications@example.com",
    "name": "Example"
  },
  "to": [
    {
      "email": "recipient@example.net"
    }
  ],
  "subject": "Welcome",
  "text": "Your account is ready."
}'

Node.js

const response = await fetch("https://api.airmailai.tech/v1/messages", {
  method: "POST",
  signal: AbortSignal.timeout(15000),
  headers: {
    Authorization: `Bearer ${process.env.AIRMAIL_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "account-481-welcome"
  },
  body: JSON.stringify({
  "from": {
    "email": "notifications@example.com",
    "name": "Example"
  },
  "to": [
    {
      "email": "recipient@example.net"
    }
  ],
  "subject": "Welcome",
  "text": "Your account is ready."
})
});

const result = await response.json();
if (!response.ok) throw new Error(result?.error?.code ?? `HTTP ${response.status}`);
console.log(result.id, result.status);

PHP

$payload = json_encode([
  'from' => [
    'email' => 'notifications@example.com',
    'name' => 'Example'
  ],
  'to' => [
    [
      'email' => 'recipient@example.net'
    ]
  ],
  'subject' => 'Welcome',
  'text' => 'Your account is ready.'
], JSON_THROW_ON_ERROR);
$request = curl_init('https://api.airmailai.tech/v1/messages');
curl_setopt_array($request, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CONNECTTIMEOUT => 10,
  CURLOPT_TIMEOUT => 20,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('AIRMAIL_API_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: account-481-welcome'
  ]
]);
$body = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
curl_close($request);
if ($body === false || $status >= 400) throw new RuntimeException('Airmail request failed');
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
echo $result['id'] . PHP_EOL;

Python

import os
import requests

response = requests.post(
    "https://api.airmailai.tech/v1/messages",
    headers={
        "Authorization": f"Bearer {os.environ['AIRMAIL_API_KEY']}",
        "Idempotency-Key": "account-481-welcome",
    },
    json={
    "from": {
        "email": "notifications@example.com",
        "name": "Example"
    },
    "to": [
        {
            "email": "recipient@example.net"
        }
    ],
    "subject": "Welcome",
    "text": "Your account is ready."
},
    timeout=15,
)
response.raise_for_status()
result = response.json()
print(result["id"], result["status"])

SMTP configuration

Use smtp.airmailai.tech:587 with STARTTLS required. Keep the generated username and password server-side. Do not use port 25, implicit TLS on 465, or plaintext authentication. Set AIRMAIL_MESSAGE_ID to a persisted RFC Message-ID such as <account-481@example.com>; keep it and the message content unchanged on a retry.

Laravel

The environment example below is for Laravel 8. For recent Symfony-based Laravel versions, use the versioned Laravel SMTP guide and require TLS explicitly.

MAIL_MAILER=smtp
MAIL_HOST=smtp.airmailai.tech
MAIL_PORT=587
MAIL_USERNAME=<AIRMAIL_SMTP_USERNAME>
MAIL_PASSWORD=<AIRMAIL_SMTP_PASSWORD>
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=notifications@example.com
MAIL_FROM_NAME=Example

PHP with PHPMailer

Install phpmailer/phpmailer with Composer and load vendor/autoload.php before running the example. Use your verified domain and an intended recipient after approval.

$mail = new PHPMailer\PHPMailer\PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.airmailai.tech';
$mail->Port = 587;
$mail->SMTPAuth = true;
$mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
$mail->Username = getenv('AIRMAIL_SMTP_USERNAME');
$mail->Password = getenv('AIRMAIL_SMTP_PASSWORD');
$mail->setFrom('notifications@example.com', 'Example');
$mail->addAddress('person@example.net');
$mail->MessageID = getenv('AIRMAIL_MESSAGE_ID');
$mail->Subject = 'Welcome';
$mail->Body = 'Your account is ready.';
$mail->send();

Node.js with Nodemailer

import nodemailer from "nodemailer";

const transport = nodemailer.createTransport({
  host: "smtp.airmailai.tech",
  port: 587,
  secure: false,
  requireTLS: true,
  auth: {
    user: process.env.AIRMAIL_SMTP_USERNAME,
    pass: process.env.AIRMAIL_SMTP_PASSWORD
  }
});
await transport.sendMail({
  from: "Example <notifications@example.com>",
  to: "person@example.net",
  messageId: process.env.AIRMAIL_MESSAGE_ID,
  subject: "Welcome",
  text: "Your account is ready."
});

Python

import os, smtplib, ssl
from email.message import EmailMessage

message = EmailMessage()
message["From"] = "Example <notifications@example.com>"
message["To"] = "person@example.net"
message["Subject"] = "Welcome"
message["Message-ID"] = os.environ["AIRMAIL_MESSAGE_ID"]
message.set_content("Your account is ready.")

with smtplib.SMTP("smtp.airmailai.tech", 587, timeout=15) as smtp:
    smtp.starttls(context=ssl.create_default_context())
    smtp.login(os.environ["AIRMAIL_SMTP_USERNAME"], os.environ["AIRMAIL_SMTP_PASSWORD"])
    smtp.send_message(message)