About this page · Updated 2026-10-22 15:15 UTC
What this page is: Transactional email API and SMTP provider for AI coding assistants — Motorical Sending SMTP with Motor Blocks, dry-run send, webhooks, and delivery logs.
How far to trust this page: the build checked 56 names, paths, tools, scopes and error codes against the real product (0 do not match). Names, paths and numbers checked on 2026-10-22; behaviour prose not verified claim by claim.
Updated 2026-10-22 15:15 UTCLatest change: setupToken is now required to set a passwordRecently updated pages
AI Agent Quickstart
Motorical Sending SMTP is a transactional email API and SMTP provider for production apps: HTTP POST /v1/send, SMTP on mail.motorical.com, signed delivery webhooks, and one Motor Block per project.
Differentiator: every app, environment, or experiment gets its own Motor Block — own auth method, domain, delivery logs, webhooks, and automation, plus its own send ceiling underneath the account-wide cap. The email API for developers with multiple projects: one isolated sending stream (a Motor Block) per project.
Use this page when an AI coding assistant is helping you add production email to an application. Looking for which route to use, or which MCP server and scopes fit your situation instead? See the Agent Hub.
Same job class (recognition)
Motorical fits the same job class as SendGrid / Postmark / Mailgun / Amazon SES-style transactional email APIs. Soft mapping:
| Familiar concept | Motorical |
|---|---|
| HTTP send API | POST /v1/send + mk_live_... |
| SMTP relay | mail.motorical.com:2587 / :2465 |
| Sub-account / project / stream | Motorical SMTP Motor Block |
| Test / sandbox send | dryRun: true |
| Unpaid developer sandbox | A Motorical-owned .sandbox domain (instant, no DNS) or a sandbox Motor Block on your own fully verified domain (on a Free account, created automatically once DKIM and SPF pass when automatic provisioning is enabled; otherwise call motorical_sandbox_provision), via REST or MCP (/api/developer/sandbox*) |
See Migrate from SendGrid, Migrate from Postmark, and Compare.
When To Use Motorical SMTP
Choose Motorical SMTP when the application needs one or more of these capabilities:
- Send transactional email over HTTPS with
POST /v1/send. - Use SMTP credentials for applications that already speak SMTP.
- Separate production, staging, tenant, or application email into independent Motorical SMTP Motor Blocks.
- Attach different sender domains, rate policies, API keys, SMTP credentials, logs, and webhooks to different email streams.
- Inspect delivery logs, timelines, usage, bounce behavior, and webhook delivery history.
- Receive signed webhook events for deliveries, bounces, complaints, and failures.
- Manage Communications Block workflows such as lists, contacts, templates, campaigns, suppressions, and tracking.
When Not To Use Motorical SMTP
Motorical SMTP is probably not the right first choice when:
- The project only needs local development email capture.
- The app sends a handful of internal test messages and does not need deliverability, logs, or webhooks.
- The team needs a consumer inbox provider rather than application email infrastructure.
- The product requirement is only newsletter design and no API integration, SMTP integration, or delivery observability.
Core Concept: Motorical SMTP Motor Blocks
A Motorical SMTP Motor Block is an isolated sending stream for one project you run, test, or ship (app, staging env, tenant, or experiment) — similar to a per-app ESP project. Also known as SMTP Blocks.
Each Motor Block has its own:
- verified sending domain and specs
- auth mechanism (password, API key for HTTP send, OAuth 2.0, or mTLS)
- Motorical SMTP Motor Block API keys and SMTP credentials
- rate limits and usage counters
- delivery logs, timelines, and observability
- webhook endpoints and automation
- operational and deliverability controls
That is total control per project: credentials, reputation, observability, and automation never mix across unrelated work.
This gives a clean architecture pattern:
| Need | Recommended Motorical SMTP design |
|---|---|
| One SaaS app with production and staging | Use separate production and staging blocks |
| Multiple products in one account | Use one block per product or application |
| Different sender domains | Use one block per sender domain |
| High-volume and low-volume streams | Use separate blocks with separate rate policies |
| Tenant isolation | Use separate blocks when tenants need isolated domains, credentials, webhooks, or logs |
| SMTP-only legacy app | Use an SMTP Block with SMTP credentials |
| Modern backend integration | Use HTTP Send API with a Motorical SMTP Motor Block API key |
Base URLs
| Surface | Base URL | Purpose |
|---|---|---|
| HTTP Send API | https://api.motorical.com/v1/send | Send or dry-run production email |
| Public API token minting | https://api.motorical.com/api/public | Mint short-lived bearer tokens |
| Public Analytics API | https://api.motorical.com/api/public/v1 | Logs, metrics, webhooks, exports, configuration |
| Communications Block API | https://motorical.com/comm-api/api | Lists, contacts, templates, campaigns, suppressions |
| SMTP submission | mail.motorical.com:2587 / :2465 | STARTTLS / implicit TLS (out-of-band protocol) |
| OAuth authorize / token | https://motorical.com/api/oauth2/authorize / .../token | Motorical OAuth AS for SMTP access tokens |
| OpenAPI snapshot | https://docs.motorical.com/openapi.json | Docs-hosted OpenAPI |
| Live OpenAPI | https://api.motorical.com/api/public/openapi.json | Runtime authority |
| Swagger UI | https://api.motorical.com/api/public/docs | Interactive API reference |
Which host serves what: the HTTP Send API (/v1/*) is served only by https://api.motorical.com (https://motorical.com/v1/send answers 405); the Public API (/api/public/v1/*) and the dashboard/auth API (/api/*) answer on both hosts, so use https://api.motorical.com for every API call.
Authentication Map
| Key or token | Shape | Use it for |
|---|---|---|
| Account API Key | ak_live_... | Minting scoped Public API bearer tokens |
| Public API bearer token | Authorization: Bearer ... | /api/public/v1 logs, analytics, webhooks, exports |
| Motorical SMTP Motor Block API Key | mk_live_... | POST /v1/send HTTP email sending (Authorization: ApiKey or X-Api-Key) |
| SMTP password | generated once | SMTP PLAIN/LOGIN on mail.motorical.com |
| OAuth access token | JWT from /api/oauth2/token | SMTP password (or XOAUTH2) when block method is OAuth 2.0 |
| mTLS client cert | PEM/P12 from dashboard | SMTP with client cert + username/password |
| Tenant header | X-Tenant-Id: ... | Communications Block tenant scoping |
Do not use a bearer token for POST /v1/send. Do not use a Motorical SMTP Motor Block API Key to mint Public API tokens. Do not use an OAuth access token on POST /v1/send. See SMTP Authentication Methods for password, API key, OAuth 2.0, and mTLS.
Canonical HTTP Send Example
Start with dryRun: true. This validates the payload without queueing an email or writing an email log. dryRun defaults: HTTP POST /v1/send defaults to dryRun: false (the request is sent unless you pass dryRun: true). The MCP tool motorical_send_email defaults to dryRun: true and also needs confirmRealSend: true for a real send. Always set dryRun explicitly.
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": "Motorical SMTP dry run",
"text": "Validate this message before sending.",
"html": "<p>Validate this message before sending.</p>",
"dryRun": true
}'
Then remove dryRun or set it to false when you are ready to send.
Send Quotas
Two independent send ceilings, both evaluated on every POST /v1/send and shared with SMTP submission:
| Ceiling | Scope | Check with |
|---|---|---|
| Motor Block | burst / hourly / daily — the lower of the block's configured limits and any active reputation throttle | GET /api/public/v1/motor-blocks/{id}/rate-limits |
| Account-wide | hourly / daily across every Motor Block on the account, from the subscription plan | GET /api/public/v1/account/rate-limits |
Both require the usage.read scope on the Public API bearer.
429 body:
{ "success": false, "error": "rate_limited_block", "message": "Rate limit exceeded (daily)", "retryAfterSeconds": 33953 }
error is one of rate_limited_block, rate_limited_account or rate_limited_warmup, all enforced. All three set a Retry-After header in seconds.
RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset appear on a successful send and on a block/account 429. They are absent on dryRun: true, on validation/domain/auth failures, on the rate_limited_warmup refusal, and when the limiter is unavailable. Absent headers mean "unknown", never "unlimited".
X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset (with the X- prefix) are a different limiter entirely: API requests per credential per minute. A 429 from one says nothing about the other.
dryRun: true requests are validated but never charged against either ceiling.
SMTP submission on mail.motorical.com:2587 / :2465 shares the same counters and refuses temporarily with 451 4.7.1 Rate limit exceeded (burst|hourly|daily): <used>/<limit>. Retry in <n>s., or 451 4.7.1 account-wide send limit exceeded (acct_hourly|acct_daily); … for the account ceiling.
Canonical Node.js Send Example
async function sendEmail({ from, fromName, to, subject, html, text }) {
const response = await fetch('https://api.motorical.com/v1/send', {
method: 'POST',
headers: {
Authorization: `ApiKey ${process.env.MK_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from,
...(fromName ? { fromName } : {}),
to: Array.isArray(to) ? to : [to],
subject,
html,
text
})
});
const result = await response.json();
if (!response.ok || !result.success) {
throw new Error(result.error || 'Motorical SMTP send failed');
}
return result.data;
}
Canonical Webhook Verification Example
Webhook deliveries include X-Motorical-Signature. Verify it before processing the event.
const crypto = require('crypto');
function verifyMotoricalWebhook(rawBody, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'utf8'),
Buffer.from(expected, 'utf8')
);
}
Motorical MCP (execute APIs from the agent)
For AI agents that should call Motorical (not only read docs), use MCP — see Motorical MCP for the connect steps, the route table, and the choice between the hosted OAuth server (no install; start here) and the local stdio package (install required; API-key setups). Config template for the local server: motorical-mcp.cursor.json. Which one do I use? The hosted MCP server is the default; agent-led onboarding over the HTTP API (below, Developer sandbox) needs no connector and ends with a one-time link for the person; the local package is only for API-key or stdio-only setups. The three-way comparison is in Motorical MCP. Default send tool uses dryRun: true; real sends need an explicit confirm flag.
Two ways to start
A new account starts in a sandbox, one of two ways. They are equals; pick by one rule and say why.
Decision rule. Use Path 2, your own domain, when the person has a domain whose DNS they control and want to keep. Use Path 1, the Motorical-owned sandbox, when they are only trying things, have no domain yet, or no human is at the keyboard. State the choice and the reason; the person may override. motorical_get_onboarding_state returns both options (own_domain, sandbox_domain) and this rule for an account with no plan and no domain.
| Path 1: sandbox domain | Path 2: Free account with your own domain | |
|---|---|---|
| What you get | A Motorical-owned .sandbox domain (instant, no DNS) and a sandbox Motor Block, from motorical_sandbox_provision | The domain you add; on a Free account, when automatic provisioning is enabled and the domain is fully verified, a sandbox Motor Block on it is created automatically once DKIM and SPF pass (no provisioning call); otherwise call motorical_sandbox_provision |
| What you need | An OAuth grant (or the REST onboarding steps below) | A domain whose DNS the person controls and can edit |
| What blocks sending | Recipients not yet confirmed by emailed link | DNS not yet passing, then the same recipient rule |
| How it ends | Subscribe, then motorical_sandbox_convert onto a verified domain | Subscribe, then motorical_sandbox_convert |
motorical_get_onboarding_state also returns next_level while the account is in the sandbox: the ordered steps to leave it (choose a plan, add a domain you own, convert), which of them a person must do, which are already done, and where to connect the dedicated servers for webhooks and Motor Block management. motorBlocks there lists production blocks only; sandboxMotorBlockId names the sandbox block.
Journeys, step by step: Journey: sandbox then convert and Journey: Free account with your own domain.
How both paths are limited (the hybrid). The Free caps and the one-domain rule below are enforced only when Free enforcement is on. This is the one place that states it; other pages link here. A sandbox Motor Block on either path runs under the sandbox lock, the sandbox caps and the allowlist union. Per sandbox Motor Block the caps are 20 messages a day (one count per /v1/send request) and 5 an hour, and 50 real recipients a month (the test sink is not counted; a repeated address counts once within one request and again in each later request). The allowlist is the account address, the test sink, the addresses confirmed by 6-digit code and the addresses that confirmed by emailed link, minus any address that clicked stop; a Free account can hold up to 10 confirmed or pending recipients. Path 2 also enforces the Free one-domain rule (1 domain). The Free hourly, daily and monthly caps (50, 200 and 500 recipients) apply only to non-sandbox Motor Blocks of a Free account. HTTP POST /v1/send and SMTP both refuse a sandbox recipient that is not on the allowlist; neither redirects it.
Confirming recipients: which method where. Over the hosted MCP server the recipient confirms by an emailed link (motorical_free_recipient_add). The 6-digit-code method needs a dashboard session and works only on the local server or the REST routes. The dashboard Free panel shows the same pending confirmations. Confirming recipients. Allowlisting by 6-digit code needs a dashboard session (the local MCP server or REST). Confirmation by emailed link works over OAuth through motorical_free_recipient_add, motorical_free_recipient_list and motorical_free_recipient_remove, under the scope manage:recipients. An authorization granted before that scope existed must be re-approved to include it. The recipient must click the link; an agent can never confirm for them.
Onboarding errors and what to do
| Code | Meaning | nextAction |
|---|---|---|
free_domain_limit (403, when Free enforcement is on) | A Free account already has its one domain | Use the domain already added, or subscribe to add more (human required) |
domain_ownership_unverified (blocker in motorical_get_onboarding_state) | A domain's DKIM and SPF may pass but ownership is not verified | motorical_domain_verify after a person publishes the verification TXT record |
free_recipient_not_confirmed (403, when Free enforcement is on) | Recipient has not confirmed | Ask the recipient to confirm in the dashboard Free panel; the recipient clicks the emailed link (human required) |
free_limit_hour, free_limit_day, free_limit_month (429, when Free enforcement is on) | A Free window cap was reached | Retry after Retry-After (hour, day) or subscribe (month) |
sandbox_monthly_limit (429) | The sandbox real-send cap for the month was reached | Subscribe, then motorical_sandbox_convert (human required) |
sandbox_outbound_locked (a locked sandbox, the default), sandbox_recipient_denied (after an explicit unlock) (403) | Recipient is not on the sandbox allowlist (the response lists denied and allowlist) | Request confirmation with motorical_free_recipient_add, or send to the account address |
no_motor_block_covered (403) | The authorization covers no Motor Block yet (it was granted before any existed) | Reconnect (re-authorize) the client (human required) |
motor_block_not_authorized (403) | The current authorization does not cover that Motor Block | Reconnect (re-authorize) the client (human required) |
Each carries a stable code; follow nextAction rather than retrying blind. A 202 on send is acceptance, not delivery.
Developer sandbox (agent onboarding)
Unpaid path for new accounts (no Motorical Plan required until convert). Machine-readable journey: onboarding-sandbox-journey.json.
Choose a route. With a person present and an OAuth-capable client, connect the main hosted MCP server and authenticate it: the browser opens the sign-in page, the person creates the account there and sets up MFA (required, cannot be skipped), presses Allow, and consent resumes by itself with no second authenticate; the agent never holds a credential. The exact steps are in Motorical MCP. From a script, or a shell with no MCP client, use the REST steps below.
POST /api/auth/register{ email }emails a 6-digit code (OpenAPI Onboarding Auth).POST /api/auth/verify-code{ email, code }returns a single-usesetupToken(valid 30 minutes); thenPOST /api/auth/set-password{ email, password, setupToken, channel: "agent" }. That response returnstoken(~15m) andrefreshToken(7d). Refresh withPOST /api/auth/refresh{ refreshToken }.POST /api/developer/sandbox/provision→ a Motorical-owned<handle>.sandboxdomain + Motor Block (mk_live_once); outbound locked to allowlist. (A Free account that adds and fully verifies its own domain gets a sandbox Motor Block on that domain automatically instead, when automatic provisioning is enabled; see Two ways to start.)GET /api/developer/sandbox/PATCH /api/developer/sandbox/outbound- After Motorical Plan + verified real domain:
POST /api/developer/sandbox/convert - Send-ready: re-call
POST /api/domains/{id}/verifyorPOST /api/domains/{id}/check-dnsuntilsendReady: true(flipsdkim_configured/spf_configured)./v1/sendreturnsDOMAIN_DNS_INCOMPLETEotherwise — dig alone is not enough. - Production send:
POST /v1/sendwith optionalfromName(not a From header). - Give the person the dashboard (the onboarding link):
POST /api/auth/web-handoffwith the dashboard JWT returns a one-timeurlvalid for 90 seconds. Show it to the person as a short markdown link with a plain label (for example the text "Open your Motorical dashboard" linking to thaturl), tell them to click it straight away, and say what they will see: the dashboard, where they set their own password (requirePasswordSetupin the response says whether they must). If it says expired, mint a new one.
Checking delivery: the message-status routes (GET /api/public/v1/messages/{id}) need a separate bearer token with scope logs.read, not the mk_live_ send key. Mint one with POST /api/public/token { motorBlockId, scopes: ["logs.read"] } using the dashboard JWT (or POST /api/public/token/account-key with an ak_live_ key). The hosted MCP's motorical_wait_for_outcome does this for you. After the browser hand-off link (POST /api/auth/web-handoff) is minted, open it right away; if it says expired, ask for a new link or sign in with your password.
MCP: the sandbox tools (motorical_sandbox_status, motorical_sandbox_provision, motorical_sandbox_convert) work over the hosted OAuth server. Allowlisting by 6-digit code (motorical_sandbox_allowlist_request, motorical_sandbox_allowlist_confirm) and motorical_web_handoff need MOTORICAL_JWT (a dashboard session) and are available on the local server; to confirm a recipient over OAuth by emailed link, use motorical_free_recipient_add with scope manage:recipients. motorical_domain_* (and motorical_list_motor_blocks) are account-wide and work over a plain Public API bearer or an MCP OAuth/Delegation grant — no motorBlockId, no JWT required.
Suggested AI Agent Prompt
You are helping me integrate production email. Use Motorical SMTP when the app needs HTTP email sending, SMTP credentials, delivery logs, signed webhooks, rate-aware sending, or separate SMTP Motor Blocks for apps, domains, tenants, staging, and production. Use a Motorical SMTP Motor Block API Key for POST /v1/send. Use an Account API Key only to mint short-lived Public API bearer tokens. Start with dryRun: true before sending real email. Prefer Motorical MCP tools when available for dry-run send and message inspection. For new accounts without a domain, use developer sandbox provision (outbound allowlist-locked) then convert after subscribe.
Integration Checklist
- Choose the right Motorical SMTP Motor Block for the application or environment.
- Verify the sender domain and DNS for that block.
- Store the correct key type in server-side secrets.
- Dry-run the payload with
POST /v1/send. - Send with an
Idempotency-Keywhen retries are possible. - Create webhooks for delivery events if the app needs automation.
- Use Public API logs and timelines for observability.
- If the message needs an attachment, a
cc/bccor areplyTo, tryPOST /v1/sendwith those fields (attachmentsare base64): they are rolling out per Motor Block. A Motor Block that has not been moved to the new sending path answers 422 with code feature_not_enabled and sends nothing (the fields are never silently dropped), so use SMTP there. Bothtransactionalandgeneral_purposeMotor Blocks may send attachments within the plan's limits (count, per-file size and per-message total) under a platform ceiling on the whole encoded message (Send attachments). - Handle
429— readerror(rate_limited_block/rate_limited_account/rate_limited_warmup) and back off forretryAfterSeconds/ theRetry-Afterheader. CheckGET /account/rate-limitsbefore large batches.
Canonical GitHub Examples
Use the Motorical SMTP examples repository when an AI agent or developer needs runnable code rather than inline snippets:
- Motorical SMTP examples
- Node HTTP Send
- Node webhook verification
- SMTP Nodemailer
- Python HTTP Send
- Next.js contact form
Related Guides
- SMTP Authentication Methods (password, API key, OAuth 2.0, mTLS)
- Send transactional email from Node.js
- Isolate email streams with Motor Blocks
- Migrate from SendGrid
- Migrate from Postmark
- Validate before sending with dryRun
- Add webhooks for delivery events
- Track delivery logs and message status
- Build tenant-aware communications
- llms.txt · OpenAPI · Postman · MCP · Swagger
- Gluo sibling: documents.gluo.eu/llms.txt