About this page · Updated 2026-11-05 16:07 UTC
What this page is: Sending email and checking the result: every tool on the `transactional` MCP server with its scope, inputs and an example call. A slice of the full MCP tool reference.
How far to trust this page: the build checked 0 names, paths, tools, scopes and error codes against the real product (0 do not match). Not yet reviewed claim by claim.
Updated 2026-11-05 16:07 UTCRecently updated pages
MCP tools: Sending
Sending email and checking the result. This page is the slice of the full MCP tool reference for the transactional server (the other servers are listed on the hosted servers page). The main server carries every tool, so these entries apply there too. Failures use the shape described in MCP errors.
motorical_get_send_status
Check Send API status. Check Motorical transactional email HTTP Send API status. No auth required. Requires OAuth scope: read:analytics (see motorical_whoami for what it allows).
| Property | Value |
|---|---|
| Needs scope | read:analytics |
| Available on | Hosted servers: main, transactional; the local server too |
| Acts on | See the description |
| Not listed | When the connection does not hold the scope (the narrow servers hide it; the main server lists it marked "Needs permission") |
| REST route | GET /v1/status |
| Behaviour | Read-only; safe to repeat |
No inputs.
Returns a structured result with the fields success, message, data.
Example arguments (placeholders in angle brackets, required inputs only):
{}
motorical_send_email
Send transactional email. Send a transactional email, or validate one first. Defaults to dryRun:true: a dry run returns the resolved from, subject, recipient count and body size, plus limits (burst, hourly and daily: used, limit, remaining, reset) and warnings (stable codes such as NO_TEXT_PART, SUBJECT_LONG, OVER_LIMIT, NEAR_LIMIT, THROTTLED), so "validated" is not read as "would work". Real sends require dryRun:false AND confirmRealSend:true. Over the hosted OAuth server your grant authorizes the send and you never see a key; the local stdio server instead needs MOTORICAL_MK_API_KEY (mk_live_...). A real send returns two different ids: messageId (use it with motorical_get_message and motorical_get_message_events) and nextAction.args.taskId (use it ONLY with motorical_wait_for_outcome). Neither works in the other tool. from must be an address at the domain your Motor Block is assigned to: a verified, send-ready domain you own, or the Motorical-owned sandbox domain from motorical_sandbox_provision (see motorical_get_onboarding_state sendFrom); any local part works. Sandbox accounts only: real sends go only to the effective allowlist (see motorical_sandbox_status); a non-allowlisted recipient is refused (403 sandbox_outbound_locked or sandbox_recipient_denied), never redirected, so unlock it with motorical_free_recipient_add first. Those two tools disappear once the account has a verified domain and an active plan, so ignore this sentence if you cannot see them. cc, bcc, replyTo, headers and attachments are optional; each field says its own limits and errors. Requires OAuth scope: send:transactional (see motorical_whoami for what it allows).
| Property | Value |
|---|---|
| Needs scope | send:transactional |
| Available on | Hosted servers: main, transactional; the local server too |
| Acts on | One Motor Block (the motorBlockId input) |
| Not listed | When the connection does not hold the scope (the narrow servers hide it; the main server lists it marked "Needs permission") |
| REST route | POST /v1/send |
| Behaviour | Changes data |
| Input | Type | Required | Meaning |
|---|---|---|---|
from | string (email) | No | Defaults to MOTORICAL_DEFAULT_FROM |
fromName | string | No | Optional From display name (do not put From in headers — use this field) |
to | string (email) or array of string | Yes | - |
cc | string (email) or array of string | No | Copy recipients (Cc header), named in the header. to, cc and bcc together take at most 50 recipients and every one is checked like a to recipient (sandbox allowlist, Free-account rules, suppression; a suppressed cc/bcc is skipped and listed in data.skipped). Rolling out per Motor Block: a block without it answers 422 feature_not_enabled and sends nothing, so retry without it or tell the person |
bcc | string (email) or array of string | No | Blind-copy recipients: delivered, named in no header. Rolling out per Motor Block |
replyTo | string (email) | No | Reply-To address. Do not also set a Reply-To header. Rolling out per Motor Block |
headers | object (key/value map) | No | Extra email headers, e.g. In-Reply-To / References to thread a reply, List-Unsubscribe, X-* of your own. The platform refuses From, Sender, To, Cc, Bcc, Subject, Date, Message-ID, Content-, DKIM/authentication and X-Motorical- (400 DISALLOWED_HEADERS) |
attachments | array of object | No | Small files only, because the bytes travel through the conversation: { filename, content (base64), contentType?, contentId?, disposition? }, at most 5 files and about 500 KB in total (700000 base64 characters). Send anything larger over SMTP (see the attachments guide in the docs). An inline image takes a contentId and disposition inline; html references it as cid:<contentId>. The plan decides how many files, how large and which types, as over SMTP; a refusal names the plan and the limit (413 attachment_too_large or attachments_total_too_large, 422 too_many_attachments, attachment_type_not_allowed, content_policy_rejected). A dryRun runs the plan check but not the virus and content scan, so a real send can still be refused for the file itself. Rolling out per Motor Block: 422 feature_not_enabled where not available |
subject | string | Yes | - |
text | string | No | - |
html | string | No | - |
dryRun | boolean | No | Default true — validate without queueing |
confirmRealSend | boolean | No | Required true when dryRun is false |
idempotencyKey | string | No | - |
motorBlockId | string (uuid) | No | Required when the authorization covers more than one Motor Block |
Returns a structured result with the fields success, dryRun, idempotent, message, messageId, status, delivered, nextAction, data.
Example arguments (placeholders in angle brackets, required inputs only):
{"to":"<to>","subject":"<subject>"}
motorical_wait_for_outcome
Wait for delivery outcome. Wait for a real send's actual delivery outcome (not just the 202 acceptance). Bounded server-side wait with backoff, capped under typical client timeouts. If the result is still_pending, wait retryAfterMs and call this again with the same taskId. Requires OAuth scope: read:analytics (see motorical_whoami for what it allows).
| Property | Value |
|---|---|
| Needs scope | read:analytics |
| Available on | Hosted servers: main, transactional; the local server too |
| Acts on | See the description |
| Not listed | When the connection does not hold the scope (the narrow servers hide it; the main server lists it marked "Needs permission") |
| REST route | GET /api/public/v1/messages/{id}/recipients |
| Behaviour | Read-only; safe to repeat |
| Input | Type | Required | Meaning |
|---|---|---|---|
taskId | string | Yes | From motorical_send_email's nextAction after a real (non-dryRun) send |
includePII | boolean | No | Return unmasked recipient addresses. Requires the logs.pii scope; default false (masked). |
Returns a structured result with the fields status, retryAfterMs, result.
Example arguments (placeholders in angle brackets, required inputs only):
{"taskId":"<taskId>"}
motorical_get_message
Get message by ID. Get a message by send UUID. Auto-mints bearer if needed. Requires OAuth scope: read:analytics (see motorical_whoami for what it allows).
| Property | Value |
|---|---|
| Needs scope | read:analytics |
| Available on | Hosted servers: main, transactional; the local server too |
| Acts on | One Motor Block (the motorBlockId input) |
| Not listed | When the connection does not hold the scope (the narrow servers hide it; the main server lists it marked "Needs permission") |
| REST route | GET /api/public/v1/messages/{id} |
| Behaviour | Read-only; safe to repeat |
| Input | Type | Required | Meaning |
|---|---|---|---|
messageId | string (uuid) | Yes | - |
includePII | boolean | No | - |
motorBlockId | string (uuid) | No | - |
Returns a structured result with the fields success, data.
Example arguments (placeholders in angle brackets, required inputs only):
{"messageId":"<messageId>"}
motorical_get_message_events
Get message delivery events. Get delivery lifecycle events for a message. Requires OAuth scope: read:analytics (see motorical_whoami for what it allows).
| Property | Value |
|---|---|
| Needs scope | read:analytics |
| Available on | Hosted servers: main, transactional; the local server too |
| Acts on | One Motor Block (the motorBlockId input) |
| Not listed | When the connection does not hold the scope (the narrow servers hide it; the main server lists it marked "Needs permission") |
| REST route | GET /api/public/v1/messages/{id}/events |
| Behaviour | Read-only; safe to repeat |
| Input | Type | Required | Meaning |
|---|---|---|---|
messageId | string (uuid) | Yes | - |
includePII | boolean | No | - |
motorBlockId | string (uuid) | No | - |
Returns a structured result with the fields success, data.
Example arguments (placeholders in angle brackets, required inputs only):
{"messageId":"<messageId>"}
motorical_whoami
Who am I (account, plan, grant). Who this connection is acting for: the account (id, owner email, name), its plan (name, status, hasSubscription), account.billing (price amount in minor units + currency + interval, trial end, current period end / next renewal date, cancelAtPeriodEnd and endsAt, this month's sends against the plan cap, and paymentMethod.status ok or failing; never invoices, receipts or card details; a field it cannot resolve is null with its reason under billing.unavailable) and, for an OAuth connection, the grant: the client, the scopes it holds, the Motor Blocks it covers, when it was granted, and canAdd (permissions it could still be given, with available:false where the plan does not allow it) plus addInDashboard, the page where the person adds them. Account-scoped: no Motor Block needed. grant is null when the call is not made over an OAuth grant. Over OAuth it needs no scope, so any connection can ask what it holds, and every server lists it. Use it instead of inferring scopes from the tool list.
| Property | Value |
|---|---|
| Needs scope | No scope: any OAuth connection can call it |
| Available on | Hosted servers: main, transactional, analytics, domains, sandbox, webhooks, motorBlocks, communications; the local server too |
| Acts on | The whole account (no Motor Block needed) |
| Not listed | Never |
| REST route | GET /api/public/v1/account/whoami |
| Behaviour | Read-only; safe to repeat |
| Input | Type | Required | Meaning |
|---|---|---|---|
motorBlockId | string (uuid) | No | Optional. This operation acts on the whole account, so a Motor Block is never needed; pass one only to record which block the call was made on behalf of. |
Returns the JSON of the REST route above.
Example arguments (placeholders in angle brackets, required inputs only):
{}
motorical_integrate_send
MCP prompt, not a callable tool. Guidance for integrating Motorical transactional email (HTTP Send) safely. It takes one optional language argument (for example node, python, curl).
| Property | Value |
|---|---|
| Needs scope | send:transactional |
| Available on | Hosted servers: main, transactional; the local server too |