Home
Email Deliverability

How to Send Email via API: A Developer Guide

JSON email request moving through an authenticated API to a queued message ID

The fastest reliable way to send email via API is to get one authenticated request working, save the returned message ID, and make retries idempotent before adding batches or attachments.

That order matters. A successful API response can confirm that a message is queued, but delivery remains a later event. Your integration needs to track both states.

Send one email via API

Sendmux accepts a JSON POST at its documented HTTP Sending API endpoint. The current request schema requires from, to, subject, and html_body. A plain text alternative is optional but useful for clients that prefer it.

curl -X POST https://smtp.sendmux.ai/api/v1/emails/send \
  -H "Authorization: Bearer smx_mbx_your_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: receipt-2026-001" \
  -d '{
    "from": { "email": "billing@example.com", "name": "Billing" },
    "to": { "email": "user@example.net", "name": "Jane Doe" },
    "subject": "Your receipt",
    "html_body": "<p>Your receipt is ready.</p>",
    "text_body": "Your receipt is ready."
  }'

A successful Sendmux request returns 200 OK with a queued message_id. Store that ID beside your own business record. It gives support and delivery workflows a common reference later.

Field names differ across email APIs. Copying a sample from another provider and changing only the URL is likely to fail at validation, so use the current schema for the API you are calling.

Keep authentication scoped and server-side

Sendmux's HTTP Sending API uses a Bearer API key. The key must have email.send permission, and the sender must be authorised for its scope.

Keep the key out of browser code, mobile bundles, repositories, and logs. If a browser action needs to trigger email, call your own authenticated backend and let that service make the email API request.

Use the narrowest key that can perform the send. A send-only or mailbox-scoped key limits what a leaked credential can access. Revoke or rotate it if exposure is suspected.

OAuth solves a different problem. It can be part of connecting a user-owned provider account, but the Sendmux send request itself still uses the scoped API key described in the public HTTP guide.

Handle the response as carefully as the request

Check the response body before reporting success. Sendmux uses an ok field, structured error details, and a request ID for investigation.

ResponseWhat your integration should do
ok: trueStore the queued message_id and continue tracking delivery.
400 or 422Correct the named request field. Do not retry the same invalid body.
401 or 403Fix the key, permission, sender, or account state before retrying.
429 or 503Honour Retry-After when present and retry with the same idempotency key.
Batch 200Inspect each result because individual messages can still fail.

When something goes wrong, it's really helpful to have the response request ID handy in your logs. This ID is way more useful than just a screenshot of the error message if you need to get support.

Make every retry idempotent

Network timeouts create an awkward question: did the API receive the request before the connection failed? Sending a fresh request can produce a duplicate email.

Add a stable Idempotency-Key to the first request. If you retry the same key with the same body within 24 hours, Sendmux returns the original result instead of running the send again.

The body must remain identical. Reusing the key with changed content, or while the first request is still running, returns 409 idempotency_conflict. Wait when the operation is still in flight. Use a new key only for a genuinely new logical email.

Email API lifecycle from authenticated request to queued message ID, delivery events, and safe retry

Generate the key from a stable application action such as a receipt, notification, or workflow run. Save it before the first network call so every retry can reuse it.

Upload attachments before sending

For normal files, Sendmux recommends uploading the bytes first and placing the returned attachment_id in the email request. This keeps binary data out of the JSON body and avoids base64 expansion.

{
  "from": { "email": "billing@example.com" },
  "to": { "email": "user@example.net" },
  "subject": "Invoice attached",
  "html_body": "<p>Your invoice is attached.</p>",
  "attachments": [{ "attachment_id": "att_tz4a98xxat96iws9zmbrgj3a" }]
}

Inline base64 remains available for small content that is already in memory. It increases the request size, so it is a compatibility path rather than the default for files on disk.

The current Sendmux limits allow up to 10 attachments per email, an 18 MiB binary upload, and a 25 MB final sent message. Validate the file before upload and handle validation_error or payload_too_large without repeatedly sending the same invalid request.

Treat queued and delivered as separate states

An accepted API request starts delivery work. It does not prove that the recipient system accepted the message.

Keep the logical email ID, idempotency key, Sendmux message ID, and request ID together. Reconcile the queued message against delivery logs or signed webhook events.

For webhooks, verify the signature before acting on the body. Use the event ID to deduplicate retries, then route on the documented event type. Delivery, bounce, complaint, rejection, and delay are different outcomes and should stay distinct in your application.

This approach also handles retries properly. If there's a delayed delivery, it means the current attempt is still being retried, so sending another email at that point can result in a duplicate.

Verify the right DNS records for your route

There isn't a one-size-fits-all list for DNS settings that works for every email API request.

With Sendmux, a shared test domain requires no customer DNS. A connected sending account already authenticates at its provider. A custom domain uses the record set shown for its selected sending-only or sending-and-receiving mode.

Copy those generated records exactly and wait for verification before using the custom domain. Sendmux checks ownership, sending policy, message policy, signing, and bounce handling for both custom-domain modes. Receiving mode also adds inbound routing records.

Do not invent record values or copy them from another domain. The names and targets are tied to the domain and configuration you created.

Choose HTTP API or SMTP by integration shape

Use the HTTP API for a new integration that needs JSON responses, batch sends, attachment references, and idempotent retries. Sendmux supports up to 100 messages in one batch request, with a result for each input index.

Use SMTP when an existing tool already knows how to submit email that way and cannot call an HTTP API. Follow the provider's documented host, port, TLS mode, and authentication settings.

Both paths can send email, but they expose different control surfaces. Choose once at the integration boundary instead of translating between them inside every workflow.

Where Sendmux fits

Sendmux supports a standard transactional email API flow: authenticate, send one message or a batch, upload attachments, retry safely, and inspect delivery results.

It also supports SMTP sending and inbound mailboxes for applications that need more than outbound HTTP requests. Each path follows its documented API key and permission model without changing the basic HTTP send workflow in this guide.

Start with one idempotent test message. Once its queued and delivery states reconcile correctly, add attachments or batching one behaviour at a time.

Sources

Frequently Asked Questions

What's the minimum data needed to send an email via API?

For Sendmux's current HTTP Sending API, include from, to, subject, and html_body in an authenticated JSON POST. Other providers use different field names and body requirements, so treat their current schema as the authority.

How do I send an email with an attachment using an API?

Upload the file bytes first, then include the returned attachment_id in the send request. Sendmux also accepts inline base64 for small content already in memory, but uploaded references are the preferred path for normal files.

Do I need OAuth to send email via API?

No. Sendmux's HTTP Sending API authenticates with a Bearer API key that has email.send permission. OAuth may be part of connecting a user-owned provider account, but it is not the authentication method for the send request.

How do I stop retries from sending duplicate emails?

Send a stable Idempotency-Key with the original request, then reuse the same key and identical body when retrying. Sendmux returns the original result for that pair within 24 hours and rejects a changed body with idempotency_conflict.

What DNS records do I need before sending production email?

There is no universal record set for every route. With Sendmux, copy the exact records shown for your chosen custom-domain mode and verify them before sending. A shared test domain needs no customer DNS, while a connected sending account authenticates at its provider.

Is Sendmux suitable for a standard transactional email API use case?

Yes. Sendmux supports authenticated single and batch HTTP sends, uploaded attachment references, Idempotency-Key retries, delivery logs, and webhooks. It also provides SMTP sending and inbound mailboxes when an application needs those paths.