Quickstart

From an API key to a delivered message, in five minutes.

Five minutes, four steps, and one honest warning: three things have to be true before a send will work, and every first attempt that fails, fails on one of them.

1. Create an API key

In the dashboard, open Developer → API Keys and create one. Give it a name that says which system will use it — billing-sync, not key2 — and the narrowest scopes that let it work. For sending, that is messages:send.

The key is shown once. It starts with mk_live_ and is stored only as a hash, so nobody, including us, can read it back to you. Put it straight into your secret store.

export MAILYTE_API_KEY='mk_live_...'

2. Verify a domain

You can only send from a domain you own and have proved you own.

Add the domain under Domains, then publish the DNS records it gives you. Sending needs SPF and DKIM. It does not need MX — that is for receiving, and if your mailboxes live somewhere else you should not publish ours.

curl "$MAILYTE_BASE/api/v1/domains/yourdomain.com/dns-records" \
  -H "Authorization: Bearer $MAILYTE_API_KEY"

Publish them, then ask us to check:

curl -X POST "$MAILYTE_BASE/api/v1/domains/yourdomain.com/verify" \
  -H "Authorization: Bearer $MAILYTE_API_KEY"

DNS propagation is neither instant nor uniform. A record your own resolver can see may not be visible to ours yet. If a value you are certain about fails, wait a few minutes and call again before you go looking for a typo.

3. Add a sender

A sender is the identity a message comes from — a name and address you are allowed to send as.

This is the step people skip, and it is why POST /messages returns "The from address must be a verified Sender belonging to your organization" even when the domain is verified. A verified domain is permission to use the domain; a sender is the specific address.

curl -X POST "$MAILYTE_BASE/api/v1/senders" \
  -H "Authorization: Bearer $MAILYTE_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name": "Acme", "email": "hello@yourdomain.com"}'

4. Send

curl -X POST "$MAILYTE_BASE/api/v1/messages" \
  -H "Authorization: Bearer $MAILYTE_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "to": "ada@example.com",
    "from": "hello@yourdomain.com",
    "subject": "Your receipt from Acme",
    "html": "<h1>Thanks, Ada</h1><p>Your order is on its way.</p>",
    "text": "Thanks, Ada. Your order is on its way."
  }'
{
  "message": "Message submitted successfully",
  "data": {
    "message_id": "<01JBT8XQ2M@yourdomain.com>",
    "event_id": "01JBT8XQ2M9WYC3K4F6R7S8T9V",
    "to": "ada@example.com",
    "submitted_at": "2026-09-17T10:04:11.000000Z"
  },
  "success": true,
  "code": 200
}

A 200 means accepted, not delivered. Delivery happens asynchronously and can take anywhere from a second to several minutes depending on the receiving server. Keep the message_id — it is how you find out what happened next.

5. Confirm it arrived

curl "$MAILYTE_BASE/api/v1/email-logs/messages/<message_id>" \
  -H "Authorization: Bearer $MAILYTE_API_KEY"

You will see accepted, then delivered — or bounced with a reason. For anything beyond a one-off check, do not poll this: receive webhooks instead.

When it does not work

"The from address must be a verified Sender." Step 3. The domain being verified is not enough.

422 mentioning suppression. The recipient is on your suppression list — they have bounced, complained or unsubscribed before. Mailyte refuses these ahead of your own list logic, on purpose. See Suppressions.

403 naming a scope. Your key does not carry it. Scopes cannot be edited after creation; create a replacement with the right ones and delete the old key.

Nothing in the inbox but delivered in the log. It was accepted by the receiving server, which then filed it somewhere. Check spam, and check that you are sending a text part as well as html — a message with no plain-text alternative is treated with suspicion by most filters.

Next

Sending at volume covers batches, rate limits and backoff. Templates and variables stops you building HTML strings in application code.