Skip to main content

Transactional Email API (HTTP Send)

Use Motorical's transactional email API (POST /v1/send) when your application wants to send email over HTTPS instead of SMTP. Authenticate with a Motor Block API key. Start with dryRun: true to validate the same payload without queueing an email.

What You Need

Verified domainYour from address must use the domain attached to the Motorical SMTP Motor Block.
Motorical SMTP Motor Block API KeyUse a full mk_live_... key, not an Account API Key.
Sender addressUse a real, monitored address such as info@yourdomain.com. Optional fromName sets the inbox display name (do not put a display name in from or a From header).

:::tip Key distinction POST /v1/send uses a Motorical SMTP Motor Block API Key: Authorization: ApiKey mk_live_....

Do not use a Public API bearer token or an Account API Key for sending. :::

1. Dry-Run the Payload

Dry run validates authentication, sender domain, DNS readiness, recipient shape, subject, and body size. It does not create an email log or queue delivery work.

curl -X POST "https://api.motorical.com/v1/send" \
-H "Authorization: ApiKey $MK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "sender@yourdomain.com",
"fromName": "Acme Billing",
"to": ["recipient@example.com"],
"subject": "Dry run check",
"text": "Validate this email without sending it.",
"html": "<p>Validate this email without sending it.</p>",
"dryRun": true
}'

Expected dry-run response:

{
"success": true,
"dryRun": true,
"data": {
"status": "validated",
"acceptanceStatus": "validated",
"from": "sender@yourdomain.com",
"fromName": "Acme Billing",
"domain": "yourdomain.com",
"recipientCount": 1,
"bodySize": 42
}
}

2. Send the Email

Remove dryRun or set it to false. Add an Idempotency-Key header if your application may retry the request.

curl -X POST "https://api.motorical.com/v1/send" \
-H "Authorization: ApiKey $MK_API_KEY" \
-H "Idempotency-Key: order-12345-welcome-email" \
-H "Content-Type: application/json" \
-d '{
"from": "sender@yourdomain.com",
"fromName": "Acme Billing",
"to": ["recipient@example.com"],
"subject": "Welcome to our app",
"text": "Thanks for signing up.",
"html": "<p>Thanks for signing up.</p>"
}'

A successful send returns data.id (the send UUID) and data.acceptanceStatus: "queued". Keep data.id — it is what the message lookup and timeline endpoints take.

3. Check Delivery

Use the Public API to inspect logs and timeline events. These endpoints use a short-lived bearer token minted with an Account API Key.

Use the data.id returned by POST /v1/send as $SEND_ID.

curl -H "Authorization: Bearer $TOKEN" \
"https://api.motorical.com/api/public/v1/messages/$SEND_ID/events"

For real-time automation, create a webhook for message.delivered, message.bounced, and message.complained.

Common Errors

ErrorWhat it meansFix
401 Invalid API key formatThe key is missing, truncated, or the wrong type.Use a full mk_live_... Motorical SMTP Motor Block API Key.
403 From address domain does not matchSender domain is not attached to the Motorical SMTP Motor Block.Send from the verified SMTP Motor Block domain.
403 Domain DNS setup incompleteSPF or DKIM is not ready.Complete domain DNS setup before sending.
422 Validation errorRequired fields or body content are missing.Include from, to, subject, and at least one of text or html.
429 rate_limited_blockThis Motor Block's burst/hourly/daily send cap was exceeded.Back off and retry after retryAfterSeconds / the Retry-After header. Check GET /motor-blocks/{id}/rate-limits.
429 rate_limited_accountYour account-wide send cap was exceeded (rolling out; not yet enforced everywhere).Check GET /account/rate-limits and back off.

See Rate Limits & Retention for the full 429 contract, including headers and the account-wide rollout status.