import { createClient } from "@mailsai/sdk";
const client = createClient(); // reads MAILS_API_KEY
const result = await client.test.inbound({
agent: "hello",
from: "jordan@example.com",
from_name: "Jordan Lee",
subject: "Where is my order #10473?",
body_text: "I haven't received order #10473 yet.",
});
console.log(result);from mailsai import create_client
client = create_client() # reads MAILS_API_KEY
result = client.test_inbound(
"hello",
from_="jordan@example.com",
from_name="Jordan Lee",
subject="Where is my order #10473?",
body_text="I haven't received order #10473 yet.",
)
print(result)curl -X POST 'https://api.mails.ai/v1/test/inbound' \
-H "Authorization: Bearer $MAILS_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"agent": "hello",
"from": "jordan@example.com",
"from_name": "Jordan Lee",
"subject": "Where is my order #10473?",
"body_text": "I haven'\''t received order #10473 yet."
}'mails receiving simulate --agent hello \
--from jordan@example.com \
--subject "Where is my order?" \
--body-text "Order 10473 has not arrived."{
"name": "mails_test_inbound",
"arguments": {
"agent": "hello",
"from": "jordan@example.com",
"from_name": "Jordan Lee",
"subject": "Where is my order #10473?",
"body_text": "I haven't received order #10473 yet."
}
}{
"message_id": "rcv_01JZXA2B4C6D8E0F2G4H6J8K0M",
"thread_id": "thrd_01JZX8K3M9Q4P7VN2YB6RTDC11",
"event_id": "evt_01JZXA2B4C6D8E0F2G4H6J8K2P",
"event_type": "message.received",
"quarantined": false,
"test_mode": true,
"classification": {
"intent": "unclassified",
"entities": {},
"urgency": 0.5,
"injection_score": 0.02,
"injection_categories": [],
"sender_reputation": 0.7,
"classifier_model": "injection-scan-only"
}
}201 The simulated inbound message and its
classification.
400 Invalid request — malformed JSON or a field failed
validation. Also feature_not_enabled when this
server has a feature switched off (custom domains
before they are available).
401 Missing or invalid API key.
403 The API key lacks the required scope
(insufficient_scope), or the token belongs to an
app connected by sign-in and this operation is
closed to connected apps
(connected_app_not_allowed).
404 Resource not found in this workspace, or the agent
a send names is archived (agent_archived).
409 Conflict — duplicate resource, an in-progress
idempotent request, a draft or scheduled message
that started sending while it was being changed, or
a thread deleted for good while one of its messages
is being sent (duplicate_resource); or an agent
name more than one agent has (agent_name_conflict:
use the agent's id); or a status change on an
archived agent, since archiving cannot be undone
(agent_archived).
413 Payload too large (body_too_large): raw_base64
decodes to more than 3 MB, the most this route
takes.
429 Rate or quota limit exceeded. The body's resets_at
and retry_after_seconds say when the request can
succeed. A Retry-After header is sent only when
that is 60 seconds or less; a longer wait (an
hourly, daily or monthly cap) sends none, so retry
at resets_at or raise the limit instead of
sleeping.
500 Internal server error.Simulate an inbound email (test key)
mk_test_…).import { createClient } from "@mailsai/sdk";
const client = createClient(); // reads MAILS_API_KEY
const result = await client.test.inbound({
agent: "hello",
from: "jordan@example.com",
from_name: "Jordan Lee",
subject: "Where is my order #10473?",
body_text: "I haven't received order #10473 yet.",
});
console.log(result);from mailsai import create_client
client = create_client() # reads MAILS_API_KEY
result = client.test_inbound(
"hello",
from_="jordan@example.com",
from_name="Jordan Lee",
subject="Where is my order #10473?",
body_text="I haven't received order #10473 yet.",
)
print(result)curl -X POST 'https://api.mails.ai/v1/test/inbound' \
-H "Authorization: Bearer $MAILS_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"agent": "hello",
"from": "jordan@example.com",
"from_name": "Jordan Lee",
"subject": "Where is my order #10473?",
"body_text": "I haven'\''t received order #10473 yet."
}'mails receiving simulate --agent hello \
--from jordan@example.com \
--subject "Where is my order?" \
--body-text "Order 10473 has not arrived."{
"name": "mails_test_inbound",
"arguments": {
"agent": "hello",
"from": "jordan@example.com",
"from_name": "Jordan Lee",
"subject": "Where is my order #10473?",
"body_text": "I haven't received order #10473 yet."
}
}{
"message_id": "rcv_01JZXA2B4C6D8E0F2G4H6J8K0M",
"thread_id": "thrd_01JZX8K3M9Q4P7VN2YB6RTDC11",
"event_id": "evt_01JZXA2B4C6D8E0F2G4H6J8K2P",
"event_type": "message.received",
"quarantined": false,
"test_mode": true,
"classification": {
"intent": "unclassified",
"entities": {},
"urgency": 0.5,
"injection_score": 0.02,
"injection_categories": [],
"sender_reputation": 0.7,
"classifier_model": "injection-scan-only"
}
}201 The simulated inbound message and its
classification.
400 Invalid request — malformed JSON or a field failed
validation. Also feature_not_enabled when this
server has a feature switched off (custom domains
before they are available).
401 Missing or invalid API key.
403 The API key lacks the required scope
(insufficient_scope), or the token belongs to an
app connected by sign-in and this operation is
closed to connected apps
(connected_app_not_allowed).
404 Resource not found in this workspace, or the agent
a send names is archived (agent_archived).
409 Conflict — duplicate resource, an in-progress
idempotent request, a draft or scheduled message
that started sending while it was being changed, or
a thread deleted for good while one of its messages
is being sent (duplicate_resource); or an agent
name more than one agent has (agent_name_conflict:
use the agent's id); or a status change on an
archived agent, since archiving cannot be undone
(agent_archived).
413 Payload too large (body_too_large): raw_base64
decodes to more than 3 MB, the most this route
takes.
429 Rate or quota limit exceeded. The body's resets_at
and retry_after_seconds say when the request can
succeed. A Retry-After header is sent only when
that is 60 seconds or less; a longer wait (an
hourly, daily or monthly cap) sends none, so retry
at resets_at or raise the limit instead of
sleeping.
500 Internal server error.Body Parameters
The agent that receives the message: its name or agt_ id. An agent the workspace does not have is a 404 agent_not_found, a key tied to another agent gets a 403, and a name two live agents share is a 409 agent_name_conflict.
Sender address. Required unless raw_base64 is sent, in which case it defaults to the raw email's From.
Sender display name, up to 256 characters. Left out, it is the raw email's From name when raw_base64 is sent; otherwise the message has none.
Subject line, up to 2,000 characters. Left out, it is the raw email's Subject when raw_base64 is sent; otherwise the message has none.
Message text. Required unless raw_base64 is sent, in which case it defaults to the raw email's text.
A complete raw email (RFC 822), base64-encoded, up to 3 MB decoded. Its attachments become downloadable exactly as on real mail; from, subject and body_text default to the raw email's own.
Id (msg_…) of one of this agent's sent messages, to simulate a reply to it. The message is then marked is_thread_reply and raises reply.received, unless spf and dkim are both fail. Left out, or naming any other message, it arrives as first contact.
Pretend SPF result, taken as given (default pass).
Pretend DKIM result, taken as given (default pass). With spf, both fail simulates message.received.unauthenticated. Real mail gets that event when no DKIM signature aligned with the From domain verifies and the From domain's DMARC policy is quarantine or reject.
Drives the receive/classify half of the product with a hand-supplied envelope: runs the real classifier, threads the message, persists a received row, and emits the same typed event + webhook a real inbound would. Set in_reply_to_message_id to a prior test-send id to simulate a reply.received. Send a whole email as raw_base64 (up to 3 MB) to test attachments: from, subject and body_text then default to the email's own.
Response
Id of the received message this call stored (rcv_…); read it at GET /v1/messages/received/{id}.
The thread the message was filed in (thrd_…), chosen as for real mail: that of the message named by in_reply_to_message_id when it is this agent's, else an open thread of the agent's with the same subject that the sender is already in, else a new one. It never joins a thread holding live mail.
Id of the event this call raised (evt_…), sent to your webhooks with test_mode true; read it at GET /v1/events/{id}.
reply.received when in_reply_to_message_id named one of this agent's sent messages, message.received otherwise, and message.received.unauthenticated whenever spf and dkim are both fail.
True when classification.injection_score is 0.95 or more. The stored message then has parse_status quarantined.
Always true: the message and its event are test mail, which is never billed.
True when the message carries at least one file attachment (embedded images do not count). Only a raw_base64 email can carry one.
The raw email's attachments, when raw_base64 was sent.
Was this page helpful?