Skip to main content
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);
{
  "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"
  }
}

Simulate an inbound email (test key)

Test key only (mk_test_…).
POST/v1/test/inboundscope · send
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);
{
  "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"
  }
}

Body Parameters

agentstringrequired

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.

fromstring

Sender address. Required unless raw_base64 is sent, in which case it defaults to the raw email's From.

from_namestring

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.

subjectstring

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.

body_textstring

Message text. Required unless raw_base64 is sent, in which case it defaults to the raw email's text.

raw_base64string

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.

in_reply_to_message_idstring

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.

spfstring

Pretend SPF result, taken as given (default pass).

One of: pass, fail, unknown

dkimstring

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.

One of: pass, fail, unknown

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

message_idstring

Id of the received message this call stored (rcv_…); read it at GET /v1/messages/received/{id}.

thread_idstring

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.

event_idstring

Id of the event this call raised (evt_…), sent to your webhooks with test_mode true; read it at GET /v1/events/{id}.

event_typestring

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.

One of: message.received, reply.received, message.received.unauthenticated

quarantinedboolean

True when classification.injection_score is 0.95 or more. The stored message then has parse_status quarantined.

test_modeboolean

Always true: the message and its event are test mail, which is never billed.

has_attachmentboolean

True when the message carries at least one file attachment (embedded images do not count). Only a raw_base64 email can carry one.

attachmentsobject[]

The raw email's attachments, when raw_base64 was sent.

Show propertiesHide properties
idstring

Attachment id (att_…), unique within the message.

filenamestring

The file's name, cleaned: no path, no control characters, at most 255 characters.

content_typestring

The MIME type the sender declared, e.g. application/pdf.

sizeinteger

Size in bytes of the decoded file.

content_idstring | null

The part's Content-ID without angle brackets, which the HTML body references as cid:.

inlineboolean

True for an image embedded in the HTML body rather than attached as a file.

classificationobject
Show propertiesHide properties
intentstring

What the message wants, as the classifier read it. Fixed values when it was not read for intent: general_reply for a reply in a thread from a sender that passed authentication, unknown when a rule settled it (failed authentication, in a thread or not, or a message under 80 characters from a Gmail, Outlook, Hotmail or Yahoo address), unclassified when the agent's classify_inbound is off or the classifier could not run.

entitiesobject

Extracted entities as key→value pairs (object) — present when intent classification ran.

urgencynumber

Urgency score 0–1 (higher = more time-sensitive).

injection_scorenumber

How likely the message is a prompt-injection attempt, from 0 to 1; at 0.95 or more it is quarantined. 0.5, with scan_unavailable in injection_categories, when the scan could not run.

injection_categoriesstring[]

The kinds of injection the scan found; empty when it found none. auth_fail marks a sender that failed authentication (the message's auth_failed is true), in a thread or not, and scan_unavailable a scan that could not run.

sender_reputationnumber

Trust score for the sender, 0 to 1 (higher is more trusted): the classifier's estimate when it read the message for intent, otherwise a preset, such as 0.3 for a sender that failed authentication.

classifier_modelstring

What scored the message: a model name; a value starting rules-layer when a rule settled the intent; injection-scan-only; or scan-unavailable when the scan could not run.

Was this page helpful?