Private Email MCP connects your AI assistant (such as Claude) to your Private Email mailbox. Through it, the assistant can list your folders, list, search and read your emails, mark them read or as favorites, move them between folders or to Trash, and send, reply to and forward emails from your own address — you ask in plain language, and the assistant calls the right tools.
Getting started
You need a Private Email mailbox. Private Email MCP is available at https://mcp.privateemail.com/mcp.
How you connect depends on your AI assistant:
Claude — in Claude (web and desktop), open Settings, choose Connectors, add a custom connector, and point it at https://mcp.privateemail.com/mcp. In Claude Code, run claude mcp add --transport http privateemail https://mcp.privateemail.com/mcp, then sign in through /mcp. Claude is the client we have verified Private Email MCP to work with.
Other MCP clients — add a remote MCP server and point it at https://mcp.privateemail.com/mcp. Other clients may work, but we haven't verified them yet.
When you connect, you'll be asked to sign in with your Private Email address and approve the assistant's access to your mailbox. The assistant then acts only on that mailbox, and only through the tools below.
What the assistant can and cannot do
Email content is untrusted. Subjects, senders, previews and bodies are written by other people. Private Email MCP tells the assistant to treat them as data, not as instructions, but an email can still try to steer it: review what the assistant proposes before you approve a change.
Sent email is real email.
email_send, email_reply and email_forward send from your own Private Email address, and a sent email cannot be called back. The assistant should send only what you asked for: review the recipients and the text before you approve a send.
Plain text only. You write the text of a new email, reply or forward as plain text. You cannot upload attachments or save drafts; a forward can include the attachments of the email it forwards.
Nothing is deleted permanently. Deleting an email moves it to your Trash folder, from where you can move it back. No tool empties Trash or erases a message.
Read-only access
When you connect, you choose what the assistant may do with your mailbox:
Read and write — the assistant can use every tool in this reference, including the ones that mark, move, delete and send emails.
Read only — the assistant can list your folders, list and search your emails and open them (folder_list, email_list, email_search, email_read). It cannot mark emails, move or delete them, or send, reply to or forward emails. Opening an email leaves it unread.
With read-only access, the assistant does not see the tools it is not allowed to use. If you ask it to do something it cannot do, it will tell you to reconnect Private Email and allow write operations.
To change what the assistant may do, disconnect Private Email in your AI assistant and connect it again, then choose the access you want on the approval screen.
Terms and privacy
The agreements and policies that apply to Private Email MCP:
If you need help, contact our support.
Tools at a glance
Access: Read only retrieves information. Write changes your mailbox in a way you can change back. Sensitive write sends an email from your address, which cannot be undone.
| Tool | What it does | Access |
|---|---|---|
folder_list
|
List your folders with their unread and total counts | Read |
email_list
|
List the emails in a folder, newest first | Read |
email_search
|
Search emails by text, unread, favorite or high priority | Read |
email_read
|
Read one email and, with write access, mark it as read | Write |
email_mark_read
|
Mark an email as read or unread | Write |
email_mark_favorite
|
Mark an email as a favorite or remove the mark | Write |
email_move
|
Move an email to another folder | Write |
email_delete
|
Move an email to Trash | Write |
email_send
|
Send a new email | Sensitive write |
email_reply
|
Reply to an email, or reply to all | Sensitive write |
email_forward
|
Forward an email, with its attachments by default | Sensitive write |
How emails are identified
Every email in a list or search result carries folderFullName and uid. The other tools take these two values as folder and uid. A uid is only valid inside its folder and changes when the email is moved, so after a move the assistant uses the new uid the move returned, or lists the folder again.
The folder Virtual/All covers every folder, including Trash, Spam, Drafts and Sent. It is accepted by email_list and email_search only; each result still carries the real folder of the email.
Common workflows
Catch up on unread mail
email_search with unreadOnly: true finds the unread emails across all folders.
email_read opens the ones you ask about; reading marks them as read.
Tidy up a folder
folder_list shows the folders and their exact names.
email_list lists the emails of the folder.
email_move files an email into another folder, or email_delete moves it to Trash.
Answer an email
email_search or email_list finds the email.
email_read shows it to you, so you can decide what to answer.
email_reply sends your answer, or email_forward passes the email on to someone else.
Tool reference
Folders
Access: Read.
Lists the folders of the mailbox as a flat list, nested folders included. Use a folder's fullName as the folder argument of the other tools.
This tool takes no parameters.
{
"folders": [
{ "fullName": "INBOX", "name": "INBOX", "parentFullName": "", "unread": 3, "total": 120, "role": "inbox" },
{ "fullName": "INBOX/Receipts", "name": "Receipts", "parentFullName": "INBOX", "unread": 0, "total": 14, "role": null }
]
}
role is inbox, sent, drafts, trash, junk or archive when the folder has one, otherwise null. Nested folders are named with their parent, for example INBOX/Receipts.
Emails
Access: Read.
Lists the emails of one folder, newest first, one page at a time.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
Yes | String, 1–1024 characters: the folder's fullName, or Virtual/All |
page
|
No | Integer = 0, zero-based. Defaults to 0 |
count
|
No | Integer 1–100: emails per page. Defaults to 25 |
{
"items": [
{
"folderFullName": "INBOX",
"uid": 4821,
"from": [{ "name": "Jane Doe", "address": "jane@example.com" }],
"to": [{ "name": null, "address": "you@yourdomain.com" }],
"subject": "Invoice for October",
"date": "2026-10-14T09:12:00Z",
"previewText": "Hi, please find the invoice attached…",
"isRead": false,
"isFavorite": false,
"isAnswered": false,
"hasAttachments": true,
"importance": "Normal",
"idempotencyKey": null
}
],
"total": 120,
"page": 0,
"count": 25,
"hasMore": true
}
idempotencyKey is set on the copy Private Email saved of an email you sent: in Sent, or in Drafts when sending failed. It equals the idempotencyKey the sending tool returned, so the assistant can find the email it just sent in your Sent folder. It is null on every other email. Only Sent and Drafts are trusted for it, because an incoming email can carry any value.
Access: Read.
Searches the emails of a folder by text and filters, one page at a time. Without a folder, it searches Virtual/All.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
No | String, 1–1024 characters. Defaults to Virtual/All |
query
|
No | String, 3–255 characters: text to search for |
unreadOnly
|
No | Boolean: only unread emails |
favoritesOnly
|
No | Boolean: only favorite emails |
highPriorityOnly
|
No | Boolean: only high-priority emails |
page
|
No | Integer = 0, zero-based. Defaults to 0 |
count
|
No | Integer 1–100: emails per page. Defaults to 25 |
The result has the same shape as email_list, idempotencyKey included.
Access: Write — reading marks the email as read. With read-only access the tool only reads: the email stays unread and markedRead is false.
Reads one email: headers, attachment details and the body. The body is the cleaned-up HTML version when the email has one (bodyFormathtml), otherwise its plain text (bodyFormattext), cut at 100,000 characters (bodyTruncated). Attachments are listed, not downloaded.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
Yes | String: the real folder of the email (its folderFullName), not Virtual/All |
uid
|
Yes | Positive integer: the email's uid in that folder |
{
"message": {
"folderFullName": "INBOX",
"uid": 4821,
"messageId": "<abc123@example.com>",
"from": [{ "name": "Jane Doe", "address": "jane@example.com" }],
"to": [{ "name": null, "address": "you@yourdomain.com" }],
"cc": [],
"subject": "Invoice for October",
"date": "2026-10-14T09:12:00Z",
"body": "<p>Hi, please find the invoice attached.</p>",
"bodyFormat": "html",
"bodyTruncated": false,
"attachments": [{ "name": "invoice.pdf", "contentType": "application/pdf", "size": 48213 }],
"importance": "Normal",
"idempotencyKey": null
},
"markedRead": true
}
markedRead is false when the email was returned but marking it as read failed. idempotencyKey works as in email_list.
email_mark_read — Mark email read or unread
Access: Write.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
Yes | String: the real folder of the email, not Virtual/All |
uid
|
Yes | Positive integer |
read
|
Yes | Boolean: true marks the email as read, false as unread |
{ "folderFullName": "INBOX", "uid": 4821, "isRead": true }
Setting the same state twice is harmless. A uid that is not in the folder is not reported as an error, so the assistant takes uids from a fresh list.
email_mark_favorite — Mark email as favorite
Access: Write.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
Yes | String: the real folder of the email, not Virtual/All |
uid
|
Yes | Positive integer |
favorite
|
Yes | Boolean: true marks the email as a favorite, false removes the mark |
{ "folderFullName": "INBOX", "uid": 4821, "isFavorite": true }
Access: Write.
Moves one email to another folder of the same mailbox. Moving it to the folder it is already in is refused.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
Yes | String: the real folder of the email, not Virtual/All |
uid
|
Yes | Positive integer |
destinationFolder
|
Yes | String: the folder to move the email to, not Virtual/All |
{ "previousFolderFullName": "INBOX", "folderFullName": "INBOX/Receipts", "uid": 77 }
The email gets a new uid in the destination folder. uid is null when the server did not report it; list the destination folder to find the email. A move is never retried automatically: if it could not be confirmed, the assistant lists the folders before trying again.
Access: Write.
Moves one email to the Trash folder. The email is not erased and can be moved back; an email that is already in Trash is refused, because the only remaining step would be a permanent delete, which Private Email MCP never does.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
Yes | String: the real folder of the email, not Virtual/All |
uid
|
Yes | Positive integer |
{ "previousFolderFullName": "INBOX", "folderFullName": "Trash", "uid": 912 }
Sending
These tools send real email from your own Private Email address; the sender cannot be changed. The result only says that the mail server accepted the email for delivery, not that it was delivered.
All three share these limits:
Recipients are bare email addresses such as alice@example.com, without display names, at most 50 in total. The same address given twice counts once.
The text (body) is plain text of at most 200,000 characters. Line breaks are kept; it is not sent as HTML.
No attachments can be uploaded and no draft is saved.
Together they can send to at most 500 recipients per hour, counted over the last 60 minutes: each recipient in To, Cc and Bcc counts once, after duplicates are removed. An email that would go over that is not sent at all (application.request.tooManyRequests).
Each result carries an idempotencyKey that identifies the send. The copy saved to your Sent folder carries the same idempotencyKey in email_list, email_search and email_read, so the assistant can confirm that the email is there. Saving the copy can take a few seconds after the result.
A send is never repeated blindly. If the mail server did not confirm it (infrastructure.mailcore.outcome-unknown), the email may have been sent anyway: the assistant looks for it in your Sent folder before sending it again.
Access: Sensitive write — sends a real email, which cannot be undone.
Sends a new email.
| Parameter | Required | Type & constraints |
|---|---|---|
to
|
Yes | List of 1–50 email addresses |
cc
|
No | List of up to 50 email addresses. Defaults to none |
bcc
|
No | List of up to 50 email addresses, hidden from the other recipients. Defaults to none |
subject
|
Yes | String: a single line of at most 998 characters |
body
|
Yes | String: plain text, at most 200,000 characters |
{ "accepted": true, "idempotencyKey": "00000000-0000-4000-8000-000000000001" }
To, Cc and Bcc together hold at most 50 addresses.
Access: Sensitive write — sends a real email, which cannot be undone.
Replies to one email. The subject gets a Re: prefix (never twice), the reply is threaded under the email, and the email is quoted below your text with a header naming its sender. A very long email is quoted up to 100,000 characters and marked as truncated. Replying does not mark the email as read.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
Yes | String: the real folder of the email, not Virtual/All |
uid
|
Yes | Positive integer |
body
|
Yes | String: plain text, at most 200,000 characters |
replyAll
|
No | Boolean: true also replies to the other To and Cc recipients. Defaults to false |
{ "accepted": true, "idempotencyKey": "00000000-0000-4000-8000-000000000001" }
The reply goes to the email's Reply-To address; when there is none, or it names only you, to its sender; when that is you too, as for an email in your Sent folder, to its original To recipients. Your own address is always left out. With replyAll, the other To and Cc recipients of the email are added; your main address is left out, but your aliases are not, so a copy may reach you through one of them. The reply goes to at most 50 recipients.
Access: Sensitive write — sends a real email, which cannot be undone.
Forwards one email to new recipients. The subject gets a Fwd: prefix (never twice), and the email is quoted below your text with a header naming its sender, up to 100,000 characters. A forward starts a new conversation. Forwarding does not mark the email as read.
| Parameter | Required | Type & constraints |
|---|---|---|
folder
|
Yes | String: the real folder of the email, not Virtual/All |
uid
|
Yes | Positive integer |
to
|
Yes | List of 1–50 email addresses |
body
|
Yes | String: plain text, at most 200,000 characters |
includeAttachments
|
No | Boolean: true forwards the attachments of the email, false only its text. Defaults to true |
{ "accepted": true, "idempotencyKey": "00000000-0000-4000-8000-000000000001" }
Usage limits
Each Private Email user has two budgets, counted over a sliding window:
Sending (email_send, email_reply and email_forward together): at most 500 recipients per hour. Every recipient of an email counts once, so an email to three people uses three. An email over the budget sends nothing, but the recipients that still fitted are used up.
Everything else (folder_list, email_list, email_search, email_read, email_mark_read, email_mark_favorite, email_move and email_delete together): at most 300 calls per minute, 5,000 per hour and 25,000 per day. A call must fit all three.
Outside sending, each call counts once. A call over a budget does nothing and answers application.request.tooManyRequests, which is not retryable right away; the assistant slows down and tries again later.
Errors
When a tool fails, the assistant receives an error with a code, a detail sentence and retryable, which says whether trying again later can help. The errors you may see:
| Code | Meaning |
|---|---|
application.request.tooManyRequests
|
Too many calls in a short time; nothing was done, slow down and try again later |
business.email.same-folder
|
The destination is the folder the email is already in |
business.email.already-in-trash
|
The email is already in Trash |
business.email.trash-folder-not-found
|
The mailbox has no folder marked as Trash |
business.email.no-recipient
|
A new email or forward has no recipient |
business.email.no-reply-recipient
|
The email names nobody to reply to except you |
business.email.too-many-recipients
|
More than 50 recipients in total |
business.email.unauthorized
|
The mailbox refused access; reconnect Private Email MCP |
business.mailcore.folder-not-found
|
The folder does not exist; check folder_list |
business.mailcore.message-not-found
|
The email is not in that folder; list the folder again |
business.mailcore.quota-exceeded
|
The mailbox is full |
business.mailcore.invalid-target-folder
|
Emails cannot be moved into that folder, such as Drafts or Sent |
business.mailcore.validation-failed
|
The mailbox refused an argument; errors names each refused field and rule |
business.mailcore.rejected
|
The mailbox refused the request for another reason |
infrastructure.mailcore.timeout
|
The mailbox did not answer in time; retryable |
infrastructure.mailcore.unavailable
|
The mailbox service is unavailable; retryable |
infrastructure.mailcore.outcome-unknown
|
A move or send was not confirmed; list the folders, or look in Sent, before repeating it |
Any other infrastructure.* code |
An error in Private Email MCP itself; not retryable, try again later and contact support if it persists |
Need help? We're always here for you.