---
title: "Writing"
description: "Composing, translating and sending."
url: "https://nextmail.sh/docs/mcp/tools/writing"
area: "MCP server"
category: "Tools"
---

# Writing

Composing, translating and sending.

## Writing tools

| Tool | What it does |
| --- | --- |
| composeEmail | Write the body of an email with AI from a prompt, and with `threadId` as a reply in that thread. Returns the text; it saves no draft. |
| sendEmail | Send a new email. `translateTo` writes it in the recipient’s language; `includeOriginal` (default true) keeps what you wrote beneath the translation. |
| previewTranslation | What `translateTo` would produce (the translated subject and the exact body sendEmail would put on the wire), with nothing sent and nothing stored. |
| listTranslationLanguages | Every language `translateTo` accepts, optionally filtered by a fragment of a code, an English name or the language’s own name. |
| replyToEmail | Reply inside a thread. It works out who the reply goes to (the sender, or everyone on To and Cc when `replyAll` is true, never your own addresses), the Re: subject, the threading headers, the quoted history, and the address that received the message, which it sends from. It needs permission to send and to read threads. |
| checkEmail | How a receiving mailbox would likely rate a message before it is sent: a spam score, a phishing score and an AI-writing score, each 0 to 100, with what raised each one. Nothing is sent or stored, and it never calls a model. |
| rewriteEmail | Up to five versions of a subject or a body: shorter, longer, rephrased, more formal, more casual, or as an `instruction` says. Spends one AI action. |
| suggestSubject | A short subject line for the body of an email. Spends one AI action. |
| getReplySuggestions | Up to three short replies to the latest message of a thread, the ones the reading pane offers: a label of a few words and the reply itself, in the language of that message. Kept until another message arrives, none when the message needs no reply, and it spends no AI action. |
| readVerificationCode | The sign-in or verification code in a message you pass in, as raw MIME source or as a subject with html or text. It answers only when it is sure, so a message with two different codes or a number that could be an order gives no code. It needs no permission and never calls a model. |

> `sendEmail` takes recipients, subject, body, a `from` address, and optionally a thread or draft id. It does not currently accept attachments or custom headers. There is no fallback sender, so a send must name the address it goes out as, and one with `from` left out is refused. A draft id with no `from` sends as the address that draft was saved with, and is refused when the draft holds none.

> Saving, reading, changing and deleting drafts have tools of their own in the Drafts group, and `sendEmail` with a draft id sends one.

> `sendEmail` with `translateTo` sends immediately and nobody reads the translation first. Call `previewTranslation`, show the person you are working for what it says, then pass the subject and body they approved back to `sendEmail` with `translateTo` LEFT OUT. Passing it again translates a second time and the wording moves.

> `translateTo` takes a code (`de`), an English name ("German") or the language’s own name ("Deutsch"). One that cannot be placed refuses the call rather than sending the message untranslated. A message going out in a language its sender did not choose is the failure this refusal exists to prevent.

> Translating costs three model calls (the body, the subject, and one to work out what you wrote in) whether you preview or send, so preview once rather than per revision. `listTranslationLanguages` costs nothing; it is a table, not a model call.

> Neither tool proofreads and neither answers the message. Translation is all they do.

## Reference

### `composeEmail`

Write the body of an email with AI from prompt, an instruction or a few rough notes, in the style of the mail this workspace has sent. Give threadId to write a reply: the messages of that thread are read as context. Give draft, the body written so far, to have prompt change it instead, withSubject true to get a subject too, and send, the send options as they stand (even empty), to let prompt change the recipients, the send time, tracking, the signature or the language; times are read in timeZone, or the time zone of the account. Give from, the address it goes out as, and send.fromOptions to let prompt move it to another of those addresses, and send.encrypt when every recipient can receive encrypted mail, to let prompt turn end-to-end encryption on or off. templates true lets prompt switch the email to one of the workspace's published templates, and files true lets it attach files the workspace holds. Returns the text first, then any subject, send changes, template and files to attach, in the shape sendEmail takes; it saves no draft and sends nothing, and it spends one AI action.

- Scopes: `drafts:write`.
- The app's assistant runs it without asking.
- Toolkit: `core`.

**Inputs**

- `prompt` (`string`, required)
- `emailSubject` (`string`)
- `from` (`string`, 1 to 320 characters): The address it goes out as, so it is written as that address.
- `template` (`string`, 1 to 128 characters): The id of the template the email uses now, so prompt leaves its body alone.
- `templates` (`boolean`): Let prompt switch the email to one of the workspace's published templates.
- `files` (`boolean`): Let prompt attach files the workspace holds, found by their name.
- `withSubject` (`boolean`)
- `draft` (`string`, up to 20000 characters)
- `to` (`string[]`)
- `cc` (`string[]`)
- `bcc` (`string[]`)
- `send` (`object`)
  - `scheduledAt` (`string`, nullable, up to 64 characters): When it is set to send, as an ISO-8601 time, or null when it sends right away.
  - `tracking` (`object`): Whether opens and clicks are tracked as it stands.
    - `opens` (`boolean`)
    - `clicks` (`boolean`)
  - `signature` (`boolean`): Whether the signature is added as it stands.
  - `translate` (`object`, nullable): The language it is translated into as it stands, or null when it is not.
    - `to` (`string`, required, 2 to 60 characters): A language code such as `de`, or a language name.
  - `fromOptions` (`string[]`, up to 100 items): The addresses it may go out as. `prompt` can then move it to one of them, and the answer names it in `send.from`.
  - `encrypt` (`boolean`): Whether it is encrypted end to end as it stands. Give it only when every recipient can receive encrypted mail, so `prompt` can turn encryption on or off.
- `timeZone` (`string`, 1 to 64 characters): The IANA time zone to read times in, such as `Europe/Berlin`. Without it, the time zone in the account settings.
- `threadId` (`string`)
- `threadMessages` (`object[]`)
  - `from` (`string`, required)
  - `to` (`string[]`, required)
  - `cc` (`string[]`)
  - `subject` (`string`, required)
  - `body` (`string`, required)

Also available in: API [`POST /emails/compose`](https://nextmail.sh/docs/api/reference/emails#post-emails-compose); TypeScript [`nextmail.emails.compose()`](https://nextmail.sh/docs/sdk/reference/emails#compose); Python [`emails.compose()`](https://nextmail.sh/docs/python/reference/emails#compose); Ruby [`emails.compose`](https://nextmail.sh/docs/ruby/reference/emails#compose); PHP [`emails->compose`](https://nextmail.sh/docs/php/reference/emails#compose); Go [`Emails.Compose`](https://nextmail.sh/docs/go/reference/emails#compose); Java [`emails().compose`](https://nextmail.sh/docs/java/reference/emails#compose); C# [`Emails.ComposeAsync`](https://nextmail.sh/docs/csharp/reference/emails#compose).

### `sendEmail`

Send a new email. To answer an email, use replyToEmail instead: it works out the recipients, the subject, the threading and the quoted history from the message being answered. from is the address it goes out as, and you must name it: there is no default sender, so a send with from left out is refused rather than given an address you did not choose. The one exception is a draftId with from left out, which keeps the address that draft was written as, and is refused when the draft holds none. A draftId of a saved forward sends that forward: the forwarded email and its attachments go below your message, so the message holds only the words the user adds and never a copy of the original. What you may choose: as the owner, or with a role that reaches every address, any address on a verified domain this workspace owns; otherwise only the addresses you were given to send as. whoAmI says which applies, and listWorkspaceMembers names the addresses and whole domains each person reaches. Set translateTo to write it in the recipient's language: the subject and the body are translated before it goes and what you wrote is kept below the translation, unless includeOriginal is false. NOBODY SEES THAT TRANSLATION FIRST. This sends immediately, so call previewTranslation and show your user the result if they should read it before it leaves. A language this server cannot place is refused rather than sent untranslated. Translating costs three model calls: the body, the subject and one to work out what you wrote in. It translates only. It does not proofread the message and it never answers it. attachments takes file ids from uploadFile or listFiles, replyTo sets where answers go, signature false leaves the address's signature off, signatureId picks one of its signatures instead of the default, and scheduledAt sends it later instead of now.

- Scopes: `emails:send`.
- The app's assistant always asks first.
- Toolkit: `core`.

**Inputs**

- `to` (`object[]`, required)
  - `email` (`string`, required)
  - `name` (`string`)
- `subject` (`string`, required)
- `message` (`string`, required)
- `cc` (`object[]`)
  - `email` (`string`, required)
  - `name` (`string`)
- `bcc` (`object[]`)
  - `email` (`string`, required)
  - `name` (`string`)
- `from` (`string`)
- `threadId` (`string`)
- `draftId` (`string`)
- `translateTo` (`string`)
- `includeOriginal` (`boolean`, default `true`)
- `replyTo` (`object`): Where answers go when it should not be the from address: an email, with a name if you have one.
  - `email` (`string`, required)
  - `name` (`string`)
- `attachments` (`string[]`, up to 20 items): File ids to attach, from uploadFile or listFiles. Each goes out attached, and a large one as a download link when the address has a files domain. Leave it out when nothing is attached.
- `signature` (`boolean`): The from address's signature is added below the message, as in the app. false leaves it off.
- `signatureId` (`string`, 1 to 64 characters): Which of the from address's signatures to add, by the id listSignatures reports. Left out, new mail carries the address's default and a reply its default for replies.
- `attachmentDelivery` (`string`, one of `"mime"`, `"link"`, `"auto"`): How the files go out: mime attaches them, link sends download links, and auto, the default, links large files only when the address has a files domain.
- `scheduledAt` (`string`, up to 64 characters): An ISO 8601 time, such as 2030-01-15T09:00:00Z, up to a year ahead, to send it then rather than now. It waits in Scheduled until that time, and cancelEmail or rescheduleEmail change it before then.
- `followUpAt` (`string`, format `date-time`): An ISO 8601 time, such as 2030-01-18T09:00:00Z, to be reminded if nobody replies by then. It has to be after the message goes out and at most a year ahead. If no real reply arrives, the thread returns to the top of the inbox, unread, with a push. listFollowUps lists the reminders and cancelFollowUp cancels one.
- `trackOpens` (`boolean`): true adds an open pixel to this message and false leaves it out. Left out, the setting of the address it is sent from decides, and that is off unless the address turned it on. Set it only when the user asks to track or not to track.
- `trackClicks` (`boolean`): true sends the links in this message through the tracking domain to count clicks and false leaves every link as written. Left out, the setting of the address it is sent from decides, and that is off unless the address turned it on. A link whose text is itself an address is never rewritten.

Also available in: API [`POST /emails`](https://nextmail.sh/docs/api/reference/emails#post-emails); TypeScript [`nextmail.emails.send()`](https://nextmail.sh/docs/sdk/reference/emails#send); Python [`emails.send()`](https://nextmail.sh/docs/python/reference/emails#send); Ruby [`emails.send`](https://nextmail.sh/docs/ruby/reference/emails#send); PHP [`emails->send`](https://nextmail.sh/docs/php/reference/emails#send); Go [`Emails.Send`](https://nextmail.sh/docs/go/reference/emails#send); Java [`emails().send`](https://nextmail.sh/docs/java/reference/emails#send); C# [`Emails.SendAsync`](https://nextmail.sh/docs/csharp/reference/emails#send).

### `previewTranslation`

Answers "what would this actually say in their language, before I send it". Returns the translated subject and the exact body sendEmail would put on the wire, so the person you are working for can read it, and change it, first. Nothing is sent and nothing is stored. To send what they approved, pass the subject and body straight back to sendEmail with translateTo LEFT OUT. Their edits included, that is then word for word what leaves; passing translateTo again would translate a second time and the wording would move. It translates and nothing else: it does not proofread, it does not improve the writing, and it never answers the message. Costs three model calls, the same as sending with translateTo, so preview once rather than per revision.

- Scopes: `drafts:write`.
- The app's assistant runs it without asking.
- Toolkit: `translate`.

**Inputs**

- `message` (`string`, required, not empty)
- `subject` (`string`)
- `translateTo` (`string`, required)
- `includeOriginal` (`boolean`, default `true`)

Also available in: API [`POST /emails/translate`](https://nextmail.sh/docs/api/reference/emails#post-emails-translate); TypeScript [`nextmail.emails.translate()`](https://nextmail.sh/docs/sdk/reference/emails#translate); Python [`emails.translate()`](https://nextmail.sh/docs/python/reference/emails#translate); Ruby [`emails.translate`](https://nextmail.sh/docs/ruby/reference/emails#translate); PHP [`emails->translate`](https://nextmail.sh/docs/php/reference/emails#translate); Go [`Emails.Translate`](https://nextmail.sh/docs/go/reference/emails#translate); Java [`emails().translate`](https://nextmail.sh/docs/java/reference/emails#translate); C# [`Emails.TranslateAsync`](https://nextmail.sh/docs/csharp/reference/emails#translate).

### `listTranslationLanguages`

Every language translateTo accepts, so you never have to guess a code. Pass search to filter by a fragment of a code, an English name or the language's own name. translateTo takes any of those three forms, so this is a way to check yourself rather than a step you must take first. Costs nothing. It is a table, not a model call.

- No scope.
- The app's assistant runs it without asking.
- Toolkit: `translate`.

**Inputs**

- `search` (`string`)

### `replyToEmail`

Reply to an email inside its conversation. Use this, never sendEmail, whenever you are asked to reply to, answer or respond to an email. You give the thread, the words to add and whether it is reply or reply all; the server works out the rest from the message being answered, the same way the mail client does: who it goes to, the Re: subject, the In-Reply-To and References headers that keep it in the thread, the quoted history below your text, and the address it goes out from, which is the address of this workspace that received the message. There is no default sender, so a message none of your addresses received is refused unless you name from. Reply (the default) goes to the sender, or to their Reply-To, even when that is a colleague writing from another address of this workspace. For a message sent from here that no other address of this workspace received, it goes to the people it was sent to. Reply all also sends to everyone else on its To and Cc. Your other addresses are always left out and nobody on its Bcc is ever included. It answers the latest message of the thread unless you pass messageId. The message is plain text and is sent exactly as written. When the user handed you a saved draft of this reply, pass its draftId so that draft is deleted once the reply is sent. This sends the reply; it does not save a draft.

- Scopes: `emails:send`, `threads:read`.
- The app's assistant always asks first.
- Toolkit: `core`.

**Inputs**

- `threadId` (`string`, required, not empty): The thread to answer: an id from inboxRag, listThreads or getThread, or the thread that is open.
- `messageId` (`string`): Leave it out to answer the latest message of the thread, which is right unless the user named an earlier one. To answer an earlier message, pass its id only when a tool listed message ids for this thread, or its Message-ID header when the user gave you one. Never guess: an id this thread does not hold is refused.
- `replyAll` (`boolean`, default `false`): false, the default, answers only the person the message came from (or its Reply-To), even a colleague writing from another address of this workspace. For a message sent from here that no other address of this workspace received, it goes to the people it was sent to. true also sends to everyone else on its To and Cc, never to your own addresses. Set true only when the user says reply all, reply to everyone, or asks to keep the others on it.
- `message` (`string`, required, not empty): Only what you are adding: the body of the reply in plain text, with a blank line between paragraphs. It is sent exactly as written, so HTML tags arrive as text. No subject line, no quoted email and no signature: the quote of the message being answered and the signature are added for you.
- `from` (`string`): Leave it out. The reply goes out from the address of this workspace that received the message. Set it only when the user asks to answer from a different address of theirs.
- `addCc` (`string[]`, up to 50 items): Extra people to copy, and only when the user names them.
- `addBcc` (`string[]`, up to 50 items): People to blind copy, and only when the user names them. Nobody on the Bcc of the message being answered is ever included.
- `draftId` (`string`): The draftId of the saved draft of this reply, when the user wrote one and handed it to you. Once the reply is sent that draft is deleted, so no stale copy stays in drafts. A draft of any other thread is left alone.
- `followUpAt` (`string`, format `date-time`): An ISO 8601 time, such as 2030-01-18T09:00:00Z, to be reminded if nobody replies by then. It has to be after the message goes out and at most a year ahead. If no real reply arrives, the thread returns to the top of the inbox, unread, with a push. listFollowUps lists the reminders and cancelFollowUp cancels one.
- `trackOpens` (`boolean`): true adds an open pixel to this message and false leaves it out. Left out, the setting of the address it is sent from decides, and that is off unless the address turned it on. Set it only when the user asks to track or not to track.
- `trackClicks` (`boolean`): true sends the links in this message through the tracking domain to count clicks and false leaves every link as written. Left out, the setting of the address it is sent from decides, and that is off unless the address turned it on. A link whose text is itself an address is never rewritten.
- `attachments` (`string[]`, up to 20 items): File ids to attach, from uploadFile or listFiles. Each goes out attached, and a large one as a download link when the address has a files domain. Leave it out when nothing is attached.

Also available in: API [`POST /emails`](https://nextmail.sh/docs/api/reference/emails#post-emails); TypeScript [`nextmail.emails.send()`](https://nextmail.sh/docs/sdk/reference/emails#send); Python [`emails.send()`](https://nextmail.sh/docs/python/reference/emails#send); Ruby [`emails.send`](https://nextmail.sh/docs/ruby/reference/emails#send); PHP [`emails->send`](https://nextmail.sh/docs/php/reference/emails#send); Go [`Emails.Send`](https://nextmail.sh/docs/go/reference/emails#send); Java [`emails().send`](https://nextmail.sh/docs/java/reference/emails#send); C# [`Emails.SendAsync`](https://nextmail.sh/docs/csharp/reference/emails#send).

### `checkEmail`

Scores a message the way a receiving mailbox would, before it is sent: a spam score, a phishing score and an AI-writing score, each 0 to 100, with what raised each one. Call it on a draft before sendEmail or replyToEmail when the user wants it to land well, then fix what it names. Nothing is sent or stored, it costs nothing and it never calls a model. A low score is a good sign, not a delivery guarantee.

- Scopes: `emails:send`.
- The app's assistant runs it without asking.
- Toolkit: `core`.

**Inputs**

- `subject` (`string`, up to 998 characters, default `""`)
- `body` (`string`, required, up to 200000 characters): The body, as HTML or plain text.
- `from` (`string`): The address it will be sent from.
- `fromName` (`string`, up to 320 characters): The name it will be sent under, which the phishing check reads.
- `replyTo` (`string`, up to 320 characters): The Reply-To address, when answers should go somewhere other than from. The phishing check reads it.
- `isReply` (`boolean`): True when it answers an existing thread.
- `attachmentNames` (`string[]`, up to 100 items): The names of the files it will carry, which the phishing check reads.

Also available in: API [`POST /emails/check`](https://nextmail.sh/docs/api/reference/emails#post-emails-check); TypeScript [`nextmail.emails.check()`](https://nextmail.sh/docs/sdk/reference/emails#check); Python [`emails.check()`](https://nextmail.sh/docs/python/reference/emails#check); Ruby [`emails.check`](https://nextmail.sh/docs/ruby/reference/emails#check); PHP [`emails->check`](https://nextmail.sh/docs/php/reference/emails#check); Go [`Emails.Check`](https://nextmail.sh/docs/go/reference/emails#check); Java [`emails().check`](https://nextmail.sh/docs/java/reference/emails#check); C# [`Emails.CheckAsync`](https://nextmail.sh/docs/csharp/reference/emails#check).

### `rewriteEmail`

Rewrite a subject or the body of an email and get up to five different versions, as the rewrite menu of the composer does, in the style of the mail this workspace has sent. action is shorten, lengthen, rephrase, formal, casual or custom, and custom needs instruction to say what to change. target is body (the default) or subject. Give threadId when the text is a reply, so the rewrite fits the conversation. Nothing is saved, and it spends one AI action.

- Scopes: `drafts:write`.
- The app's assistant runs it without asking.
- Toolkit: `drafts`.

**Inputs**

- `text` (`string`, required, 1 to 100000 characters)
- `action` (`string`, required, one of `"shorten"`, `"lengthen"`, `"rephrase"`, `"formal"`, `"casual"`, `"custom"`)
- `target` (`string`, one of `"subject"`, `"body"`)
- `instruction` (`string`, up to 500 characters)
- `count` (`integer`, at least 1, at most 5)
- `threadId` (`string`)

Also available in: API [`POST /emails/rewrite`](https://nextmail.sh/docs/api/reference/emails#post-emails-rewrite); TypeScript [`nextmail.emails.rewrite()`](https://nextmail.sh/docs/sdk/reference/emails#rewrite); Python [`emails.rewrite()`](https://nextmail.sh/docs/python/reference/emails#rewrite); Ruby [`emails.rewrite`](https://nextmail.sh/docs/ruby/reference/emails#rewrite); PHP [`emails->rewrite`](https://nextmail.sh/docs/php/reference/emails#rewrite); Go [`Emails.Rewrite`](https://nextmail.sh/docs/go/reference/emails#rewrite); Java [`emails().rewrite`](https://nextmail.sh/docs/java/reference/emails#rewrite); C# [`Emails.RewriteAsync`](https://nextmail.sh/docs/csharp/reference/emails#rewrite).

### `suggestSubject`

Suggest a short subject line for the body of an email, under 100 characters, in the style of the mail this workspace has sent. Nothing is saved, and it spends one AI action.

- Scopes: `drafts:write`.
- The app's assistant runs it without asking.
- Toolkit: `drafts`.

**Inputs**

- `message` (`string`, required, 1 to 100000 characters)

Also available in: API [`POST /emails/subject`](https://nextmail.sh/docs/api/reference/emails#post-emails-subject); TypeScript [`nextmail.emails.suggestSubject()`](https://nextmail.sh/docs/sdk/reference/emails#suggestSubject); Python [`emails.suggest_subject()`](https://nextmail.sh/docs/python/reference/emails#suggestSubject); Ruby [`emails.suggest_subject`](https://nextmail.sh/docs/ruby/reference/emails#suggestSubject); PHP [`emails->suggestSubject`](https://nextmail.sh/docs/php/reference/emails#suggestSubject); Go [`Emails.SuggestSubject`](https://nextmail.sh/docs/go/reference/emails#suggestSubject); Java [`emails().suggestSubject`](https://nextmail.sh/docs/java/reference/emails#suggestSubject); C# [`Emails.SuggestSubjectAsync`](https://nextmail.sh/docs/csharp/reference/emails#suggestSubject).

### `getReplySuggestions`

Up to 3 short replies to the latest message of an email thread, the ones the reading pane offers under it, each with a label of a few words and the reply itself, written in the language of that message and in the voice of this workspace. They are kept until another message arrives, so asking again is free. Start a reply from one with replyToEmail, as it is or adapted. A thread whose latest message needs no reply, because your own reply came last or it is a newsletter, an automated notice, spam or an encrypted message, has none, and so does every thread when the workspace turned replySuggestions off in its settings.

- Scopes: `threads:read`.
- The app's assistant runs it without asking.
- Toolkit: `drafts`.

**Inputs**

- `threadId` (`string`, required, not empty)

Also available in: API [`GET /threads/{id}/reply-suggestions`](https://nextmail.sh/docs/api/reference/threads#get-threads-id-reply-suggestions); TypeScript [`nextmail.threads.replySuggestions()`](https://nextmail.sh/docs/sdk/reference/threads#replySuggestions); Python [`threads.reply_suggestions()`](https://nextmail.sh/docs/python/reference/threads#replySuggestions); Ruby [`threads.reply_suggestions`](https://nextmail.sh/docs/ruby/reference/threads#replySuggestions); PHP [`threads->replySuggestions`](https://nextmail.sh/docs/php/reference/threads#replySuggestions); Go [`Threads.ReplySuggestions`](https://nextmail.sh/docs/go/reference/threads#replySuggestions); Java [`threads().replySuggestions`](https://nextmail.sh/docs/java/reference/threads#replySuggestions); C# [`Threads.ReplySuggestionsAsync`](https://nextmail.sh/docs/csharp/reference/threads#replySuggestions).

### `readVerificationCode`

Find the sign-in or verification code in a message you pass in, with the reader that puts a code at the top of a message in Nextmail. Send the whole MIME source as raw, or the subject with html or text. It answers only when it is sure: exactly one code worded as one, so two different codes, or a number that could be an order, a booking or a promotion, give no code. It reads only what you send and cannot tell whether the sender is genuine. For mail already in the mailbox, getThread prints the code itself.

- No scope.
- The app's assistant runs it without asking.
- Toolkit: `workspace`.

**Inputs**

- `raw` (`string`, up to 5000000 characters): The whole message as MIME source. Wins over the other fields.
- `subject` (`string`, up to 998 characters): Subject line.
- `html` (`string`, up to 1000000 characters): HTML body.
- `text` (`string`, up to 1000000 characters): Plain text body.
