Skip to main content
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.messages.reply(
  "msg_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  {
    body_text: "Thanks for the update.",
    reply_all: false,
  },
);
console.log(result);
{
  "id": "msg_01JZXC1A3B5C7D9E1F3G5H7J9K",
  "agent_id": "agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9",
  "thread_id": "thrd_01JZX8K3M9Q4P7VN2YB6RTDC11",
  "in_reply_to_message_id": "rcv_01JZXA2B4C6D8E0F2G4H6J8K0M",
  "to": ["jordan@example.com"],
  "cc": [],
  "subject": "Re: Your order #10473 has shipped",
  "status": "sent",
  "cost_usd": 0.0004,
  "created_at": "2026-06-24T18:04:55.120Z"
}

Reply to a message

Replies in-thread to a sent or received message.
POST/v1/messages/{id}/replyscope · send
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.messages.reply(
  "msg_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  {
    body_text: "Thanks for the update.",
    reply_all: false,
  },
);
console.log(result);
{
  "id": "msg_01JZXC1A3B5C7D9E1F3G5H7J9K",
  "agent_id": "agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9",
  "thread_id": "thrd_01JZX8K3M9Q4P7VN2YB6RTDC11",
  "in_reply_to_message_id": "rcv_01JZXA2B4C6D8E0F2G4H6J8K0M",
  "to": ["jordan@example.com"],
  "cc": [],
  "subject": "Re: Your order #10473 has shipped",
  "status": "sent",
  "cost_usd": 0.0004,
  "created_at": "2026-06-24T18:04:55.120Z"
}

Path Parameters

idstringrequired

The message being replied to (msg_… or rcv_…).

Body Parameters

body_textstring

Plain-text body of the reply, up to 1,000,000 characters, sent as written: the original is not quoted. At least one of body_text and body_html is required, or their aliases text and html.

body_htmlstring

HTML body of the reply, up to 1,000,000 characters, sent as written. With body_text as well, the email carries both parts.

htmlstring

Alias of body_html: used when body_html is left out, ignored when both are sent.

textstring

Alias of body_text: used when body_text is left out, ignored when both are sent.

reply_allboolean

Also copy the original's other recipients: on a received message its To and Cc addresses, on one of your sent messages its Cc. They join cc after yours, each address once, never one the reply is already addressed to and never the agent's own. Left out, nobody is added.

Default: false

ccstring[]

Addresses to copy, up to 50. With reply_all, the original's other recipients join these.

bccstring[]

Addresses to blind-copy, up to 50. They receive the reply but appear in none of its headers.

tagsobject[]

Up to 10 name-value labels, kept with the reply and included in its message.sent event; they are not part of the email.

Show propertiesHide properties
namestringrequired

Tag name: 1 to 256 letters, digits, _ or -.

valuestringrequired

Tag value, up to 256 characters; it may be empty.

scheduled_atstring

Send the reply at this time instead of now: an ISO 8601 UTC time ending in Z. A time in the past sends at once.

list_unsubscribeboolean

Opt in to RFC 8058 one-click unsubscribe: the message carries List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click headers, so the recipient's mail app shows an Unsubscribe button. One click suppresses the address for your whole workspace: every later send to it from any of your agents is refused with recipient_suppressed until you allowlist it (POST /v1/suppression/allow). Turn it on for newsletters, digests and other recurring mail. Leave it off (the default) for password resets, sign-in links, receipts and anything else the recipient must keep receiving.

Needs exactly one to recipient and no cc or bcc.

Headers

Idempotency-Keystring

Replays the stored response for a repeated key (kept 24 hours), so a retried request never double-sends; the replay carries Idempotent-Replay: true. An error is kept on the key only once the mail has gone out, so a replayed error means it was sent. Once a scheduled send is stored, a failure after that keeps the message's answer on the key instead: the retry answers with the message (201) and raises its message.scheduled if the first request did not. After a failure before either, the same key sends again, as it does after a batch that stored no message and sent no mail.

Sets In-Reply-To, References, and a Re: subject server-side. A reply cannot carry attachments (422 invalid_field, param attachments): to reply with files, send with POST /v1/messages and in_reply_to_message_id. A live key cannot reply to test mail (403 test_mode_required): its people are whatever addresses a test gave, so a live reply would send them real mail. A reply to test mail goes as a test send when it is made with a test key, or from a signed-in dashboard session that sends the header X-Mails-Mode: test. That header does not change an API key's mode, so a live key that sends it gets the same 403.

Response

idstring

Message id (msg_…), the {id} in /v1/messages/{id}.

agent_idstring

Id of the agent that sent the message (agt_…).

fromstring

The agent address this was sent as — the resolved from. Read it back when you pass from as a naming hint instead of an explicit agent: it is the receipt for which identity the API picked. On a verified custom domain the message goes out from this exact address. On the shared mails.ai domain it goes out from <name>.<workspace>@send.mails.ai, and replies come back through <name>.<workspace>@in.mails.ai.

thread_idstring

The thread the message belongs to (thrd_…).

in_reply_to_message_idstring

The message this one answers: the message replied to or forwarded, or the in_reply_to_message_id the send set. Present on reply responses and on the single-message GET, when set.

tostring[]

The To recipients, always a list. On a reply they come from the original: its Reply-To or sender for a received message, its to for one of your sent messages.

ccstring[]

Cc recipients. Always present on reply responses ([] when none); on the list and the single-message GET, present when there are any.

bccstring[]

Bcc recipients. Present only on the list and the single-message GET, when there are any.

subjectstring

The subject as sent. On a reply, Re: and the original's subject, unless that already starts with Re:; on a forward, the subject you gave or Fwd: and the original's.

body_textstring

The plain-text body as sent; on a forward it includes the quoted original. Present only on the single-message GET, when there is one.

body_htmlstring

The HTML body as sent. Present only on the single-message GET, when there is one.

classifier_scorenumber

The cold-email firewall's score for the message, from 0 (clean) to 1 (cold or spam). Present on the send response, the list and the single-message GET.

statusstring

sent once handed off; delivered, bounced or complained when the receiving side reports it (with several recipients the latest report wins). delayed when a transient (soft) bounce came back: the receiving server has not taken the message yet; it is not a bounce, does not count toward the bounce rate, raises message.delayed (sent only to endpoints that list it) and may still become delivered; with no delivery confirmed within 5 days of sending, it becomes bounced. sending only while a scheduled send is going out; rejected when the send failed, or a scheduled send was refused when it came due; canceled when a scheduled send was stopped. A live send only to the reserved test address reply@test.mails.ai is delivered at once, with a message.delivered event, since it is never transmitted; with a test key it stays sent, as every test-mode send does. Either way its automatic reply arrives as reply.received (at most 3 replies in one thread; a 4th message there gets none).

One of: scheduled, sending, sent, delivered, delayed, bounced, complained, rejected, canceled

refused_recipientsstring[]

The recipients the email service refused when the message was sent, while it took the message for the others: it went to everyone else, and not to these. The message is still a send, so sending it again with the same Idempotency-Key gives this answer back and sends nothing; to reach them, check the addresses and send them a new message. Present only when there were any: on the send, batch, reply and forward responses, the list, the single-message GET and the message's message.sent event. When every recipient is refused, nothing is sent and the send fails instead.

cost_usdnumber

USD cost of the send. 0 for scheduled or test-mode sends.

ses_message_idstring

The sending provider's id for the message, which its delivery, bounce and complaint reports refer to; test-<message id> for a test-mode send. Present only on the list and the single-message GET, once the message has been handed off.

attachmentsobject[]

Name, type and size of each file the send carried; the files themselves are not kept. Present when there were any, on the send response, the list and the single-message GET.

Show propertiesHide properties
filenamestring

The file name, as given in the send's attachments.

content_typestring

The MIME type given in the send's attachments. A file fetched from its path without one takes the type the URL answered with, or application/octet-stream when it named none.

size_bytesinteger

Size of the file in bytes: content_base64 decoded, or the bytes fetched from path.

content_idstring

Only on a file shown inside the HTML body: the id its cid: names.

referencesstring[]

The References chain kept with the message: the references the send passed, or on a reply the ids of the earlier messages it answers. Present only on the single-message GET, when there is one.

metadataobject

The metadata the send passed; a scheduled send refused when it came due also carries rejected_reason and rejected_at. Present only on the single-message GET, when there is any.

tagsobject[]

The tags the message was sent with. Present when there are any, on send, batch and reply responses, the list and the single-message GET.

Show propertiesHide properties
namestring

The tag's name, as given on the send, reply or draft.

valuestring

The tag's value, as given; it may be an empty string.

sent_atstring

When the message was handed off for sending: at once for an immediate send, when it came due for a scheduled one. Present only on the list and the single-message GET, once that has happened.

delivered_atstring

When delivery was confirmed; with several recipients, the time of the latest report. Present only on the list and the single-message GET, once a delivery is confirmed.

scheduled_atstring

The time a scheduled send was set for. On send, batch and reply responses it is present only when that time was in the future; the list and the single-message GET keep it after the message has gone out or been canceled.

canceled_atstring

When the scheduled send was canceled. Present only on the list and the single-message GET, for a canceled message.

bounced_atstring

When a bounce was last reported for the message; a soft bounce, which marks it delayed, does not set it. Present only on the single-message GET.

complained_atstring

When a recipient's complaint about the message was last reported. Present only on the single-message GET.

forwarded_fromstring

Source message id (forward responses only).

test_modeboolean

True for a message sent with a test key (mk_test_…): nothing was transmitted and nothing was billed.

classifier_warningobject

Present only on a test-mode send that a live key would refuse: the cold-email firewall's verdict, reported instead of thrown. Nothing was transmitted.

Show propertiesHide properties
codestring

Always cold_email_prohibited, the error code a live key would get.

One of: cold_email_prohibited

messagestring

The verdict in words: why a live key would refuse the message, what would pass instead, and that nothing was transmitted.

scorenumber

The firewall's score for the message, from 0 (clean) to 1 (cold or spam).

reasonstring

What the message was classified as, such as cold_outreach, spam_pattern or phishing_lure.

created_atstring

When the message was created; for a scheduled send, when it was scheduled, not when it went out.

Was this page helpful?