Quickstart

Send your first email with the wemail API in minutes: create an API key, verify a sending domain, POST /v3/messages and confirm delivery via events or webhooks.

This page walks through the shortest path to a delivered email: an API key, a verified sending domain, one POST /v3/messages call and a look at what came back. Nothing here needs more than a terminal; the Console handles the two one-time steps. Expect the whole thing to take a few minutes, most of them waiting for DNS.

What you need

A wemail account (the free tier is enough), a domain or subdomain you can add DNS records to, and something that can make an HTTPS request — curl or one of the official SDKs for Node, Python, PHP, Ruby, Go, Java and C#. The code samples on the right show the same send in every language.

1. Create an API key

In the Console open API Keys → Create key. Pick a scope — full_access for setup work, send_only for the service that will actually send, read_only for dashboards — and an environment. The secret is shown once; store it in your secret manager, never in source control. Keys start with afn_live_ or afn_test_.

2. Verify a sending domain

Mail has to come from a domain you control, ideally a dedicated subdomain such as mail.acme.io so your corporate reputation and your product mail stay separate. In the Console open Domains → Add domain (or call POST /v3/domains) and publish the three DNS records it hands you: SPF authorises wemail to send for the domain, DKIM signs every message, DMARC tells receivers what to do when either fails. Propagation usually takes minutes; then press Verify or call PUT /v3/domains/{name}/verify. Production sending unlocks the moment the domain is verified.

3. Send a message

Call POST /v3/messages with the key as a Bearer token. The minimum body is from, to, subject and either html or text; tags and custom headers are optional but worth adding from day one because every event and metric can be filtered by them. wemail validates the request, checks suppressions and quota, and answers within about 80 ms with the message id and status: "queued". That response means the message is accepted and durable — delivery happens asynchronously.

jsonResponse
{
  "id": "msg_01HBYE7K9Z4PMQDR3W",
  "status": "queued",
  "created_at": "2026-05-10T09:42:18Z",
  "from": "noreply@updates.acme.io",
  "to": ["alex@example.com"],
  "tags": ["welcome", "v2"]
}

4. Confirm delivery

Three ways, from quickest to most robust. GET /v3/messages/{id} returns the current status (queued, sent, delivered, bounced, complained) with timestamps. The Activity screen in the Console shows the same message with its full event timeline, the rendered content and the raw provider response. For production, register a webhook under Webhooks → Add endpoint or POST /v3/webhooks: wemail POSTs a signed JSON event for delivered, bounced, opened, clicked, complained and unsubscribed, retries on failure, and lets you replay deliveries later.

5. Where to go next

Move the HTML into a template with merge tags so the service only sends variables. Use batch send for up to 1,000 recipients per call and an Idempotency-Key header so retries never send twice. If a legacy system can only speak SMTP, point it at the SMTP relay with the same API key as the password. Rate limits are per account: 10 requests per second on Free, 100 on Professional — see Rate limits before load-testing.

Code examples

cURL
curl -X POST https://api.wemail.io/v3/messages \
  -H "Authorization: Bearer afn_live_pK7…b9aF" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "noreply@updates.acme.io",
    "to":   ["alex@example.com"],
    "subject": "Welcome to Acme",
    "html": "<h1>Hi Alex</h1><p>Glad to have you.</p>",
    "tags": ["welcome", "v2"],
    "headers": { "X-TES-MSGID": "tes-7f3a9c" }
  }'
Node.js
import { WemailClient } from "@wemail/sdk";
const wemail = new WemailClient(process.env.WEMAIL_API_KEY);

const { id } = await wemail.sendMessage({
  from:    "noreply@updates.acme.io",
  to:      ["alex@example.com"],
  subject: "Welcome to Acme",
  html:    "<h1>Hi Alex</h1><p>Glad to have you.</p>",
  tags:    ["welcome", "v2"],
  // stamped on the email, echoed on every webhook, returned by GET /v3/messages/{id}
  headers: { "X-TES-MSGID": "tes-7f3a9c" },
});
Python
from wemail.client import WemailClient

wemail = WemailClient(api_key=os.environ["WEMAIL_API_KEY"])

msg = wemail.send_message({
    "from": "noreply@updates.acme.io",
    "to": ["alex@example.com"],
    "subject": "Welcome to Acme",
    "html": "<h1>Hi Alex</h1><p>Glad to have you.</p>",
    "tags": ["welcome", "v2"],
})
PHP
<?php
$wemail = new \Wemail\WemailClient(getenv('WEMAIL_API_KEY'));
$msg = $wemail->sendMessage([
    'from'    => 'noreply@updates.acme.io',
    'to'      => ['alex@example.com'],
    'subject' => 'Welcome to Acme',
    'html'    => '<h1>Hi Alex</h1>',
    'tags'    => ['welcome', 'v2'],
]);
Ruby
wemail = Wemail::Client.new(api_key: ENV["WEMAIL_API_KEY"])
msg = wemail.send_message(
  from: "noreply@updates.acme.io",
  to:   ["alex@example.com"],
  subject: "Welcome to Acme",
  html: "<h1>Hi Alex</h1>",
  tags: ["welcome", "v2"]
)
Go
client, err := wemail.NewClient(os.Getenv("WEMAIL_API_KEY"))
msg, err := client.SendMessage(wemail.SendMessageRequest{
    From:    "noreply@updates.acme.io",
    To:      []string{"alex@example.com"},
    Subject: "Welcome to Acme",
    Html:    wemail.PtrString("<h1>Hi Alex</h1>"),
    Tags:    []string{"welcome", "v2"},
})
Java
WemailClient wemail = new WemailClient(System.getenv("WEMAIL_API_KEY"));
SendMessage202Response msg = wemail.sendMessage(new SendMessageRequest()
    .from("noreply@updates.acme.io")
    .to(List.of("alex@example.com"))
    .subject("Welcome to Acme")
    .html("<h1>Hi Alex</h1>")
    .tags(List.of("welcome", "v2")));
.NET
var wemail = new WemailClient(Environment.GetEnvironmentVariable("WEMAIL_API_KEY"));
var msg = await wemail.SendMessageAsync(new SendMessageRequest {
  From = "noreply@updates.acme.io",
  To = new List<string> { "alex@example.com" },
  Subject = "Welcome to Acme",
  Html = "<h1>Hi Alex</h1>",
  Tags = new List<string> { "welcome", "v2" },
});
ResponseExample response
{
  "id": "msg_01HBYE7K9Z4PMQDR3W",
  "status": "queued",
  "created_at": "2026-05-10T09:42:18Z",
  "from": "noreply@updates.acme.io",
  "to": ["alex@example.com"],
  "tags": ["welcome", "v2"],
  "headers": { "X-TES-MSGID": "tes-7f3a9c" }
}