Skip to main content

API Quickstart

This guide sends one transactional email through the Mailtarget Transmission API. Allow about ten minutes if your sending domain is already verified, longer if you need to set up DNS first.

Before you start

You need:

  1. A Mailtarget account. If you do not have one, sign up in the dashboard.
  2. A verified sending domain. Add a sending domain in the dashboard, publish the SPF, DKIM, and tracking-domain CNAME records, and verify. See Sending Domains.
  3. An API key with Send via API permission. Create the key in the dashboard. Read Authentication for permission scope and IP allowlist guidance.

Export the key as an environment variable so you do not paste it into shell history.

export MAILTARGET_API_KEY="your_api_key_here"

The first request

The Transmission API endpoint is:

POST https://transmission.mailtarget.co/v1/layang/transmissions

Send a minimal request. Replace the from address with your verified sending domain and the to address with one you can read.

curl https://transmission.mailtarget.co/v1/layang/transmissions \
-X POST \
-H "Authorization: Bearer $MAILTARGET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject": "Hello from Mailtarget",
"from": {
"email": "you@your-verified-domain.com",
"name": "Your Name"
},
"to": [
{ "email": "recipient@example.com" }
],
"bodyText": "If you can read this, the integration works.",
"bodyHtml": "<p>If you can read this, the integration works.</p>"
}'

A successful response returns the transmissionId and a 200-class status.

{ "transmissionId": "abc123" }

Persist the transmissionId in your application. It is the handle you use to correlate webhook events later.

Common first-send errors

SymptomLikely causeFix
401 UnauthorizedMissing or wrong Authorization header.Check the header includes Bearer and the key is correct.
403 ForbiddenKey does not have Send via API scope, or the IP is outside the allowlist.Update the key scope or the allowlist in the dashboard.
422 Unprocessable Entity with Domain not verifiedThe from email is on a domain that has not finished verification.Verify the sending domain. See Sending Domains.
422 Unprocessable Entity with Recipient suppressedThe recipient address is on the account suppression list.Use a different test recipient.
429 Too Many RequestsAccount-level rate limit exceeded.Wait for the duration in Retry-After, then resend.

The full error catalog is in Errors and Rate Limits.

Language examples

The same request shape, in a few languages.

Node.js

const res = await fetch("https://transmission.mailtarget.co/v1/layang/transmissions", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.MAILTARGET_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
subject: "Hello from Mailtarget",
from: { email: "you@your-verified-domain.com", name: "Your Name" },
to: [{ email: "recipient@example.com" }],
bodyText: "If you can read this, the integration works.",
}),
});

const json = await res.json();
console.log(json.transmissionId);

Python

import os, requests

res = requests.post(
"https://transmission.mailtarget.co/v1/layang/transmissions",
headers={
"Authorization": f"Bearer {os.environ['MAILTARGET_API_KEY']}",
"Content-Type": "application/json",
},
json={
"subject": "Hello from Mailtarget",
"from": {"email": "you@your-verified-domain.com", "name": "Your Name"},
"to": [{"email": "recipient@example.com"}],
"bodyText": "If you can read this, the integration works.",
},
)
res.raise_for_status()
print(res.json()["transmissionId"])

Go

package main

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

func main() {
body, _ := json.Marshal(map[string]any{
"subject": "Hello from Mailtarget",
"from": map[string]string{"email": "you@your-verified-domain.com", "name": "Your Name"},
"to": []map[string]string{{"email": "recipient@example.com"}},
"bodyText": "If you can read this, the integration works.",
})

req, _ := http.NewRequest(
"POST",
"https://transmission.mailtarget.co/v1/layang/transmissions",
bytes.NewReader(body),
)
req.Header.Set("Authorization", "Bearer "+os.Getenv("MAILTARGET_API_KEY"))
req.Header.Set("Content-Type", "application/json")

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

var out struct { TransmissionID string `json:"transmissionId"` }
json.NewDecoder(res.Body).Decode(&out)
fmt.Println(out.TransmissionID)
}

PHP

<?php
$ch = curl_init("https://transmission.mailtarget.co/v1/layang/transmissions");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("MAILTARGET_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"subject" => "Hello from Mailtarget",
"from" => ["email" => "you@your-verified-domain.com", "name" => "Your Name"],
"to" => [["email" => "recipient@example.com"]],
"bodyText" => "If you can read this, the integration works.",
]),
]);
$response = curl_exec($ch);
echo $response;

What is next

After the first send works:

  1. Wire Webhooks so your application learns the delivery outcome.
  2. Read the Transmission API reference for the full request body, including templates, substitution data, attachments, and metadata.
  3. Read Errors and Rate Limits before you write retry logic.