MCP server
PineMail is an MCP server (Model Context Protocol) at https://pinemail.app/mcp. An AI agent or coding assistant that speaks MCP connects to it with one of your API keys and gets the public API as tools: send email, add and check domains, create mailboxes, read the email log, read and search a mailbox, write drafts, send from a mailbox, read its calendar, and list buckets and files. A person connects with a login instead of a key, and the assistant gets their own mailboxes with the scopes they allow. The key decides which tools the agent sees, so a sending key gives it send_email and cancel_email and nothing else.
Connect with a login
- In the assistant, add an MCP server or a connector with the URL
https://pinemail.app/mcp. - PineMail's sign-in opens. Sign in, and tick what the assistant may do.
- Ask it for something, such as "summarise what came in today" or "write a reply to the last mail from the accountant". Replies end up as drafts in PineMail unless the owner allows sending.
For your own mail, connect the way you connect any app: give the client the URL https://pinemail.app/mcp, sign in to PineMail when it asks, and tick what it may do. PineMail is an OAuth authorization server for MCP (revision 2026-07-28, with client metadata documents), so a client that supports MCP connections with a sign-in finds everything by itself. The assistant then sees the mailboxes you see, as owner or as a mailbox login, with the scopes you allowed: read and search, write drafts, send, read the calendar. Each connection is listed under Account → Connected apps, where you disconnect it; it stops at once.
What the assistant reads leaves PineMail to the assistant's provider, under that provider's terms, so connect only what you would show it yourself. The account owner decides for everyone on the account whether a connected assistant may send at all, under Account → Assistants. An account starts with "Drafts only": sending is refused even when it was allowed at connection, and the assistant is told to write a draft instead. API keys are not affected: their scopes are the owner's own choice when the key is made.
Claude Code, with a login
Connect with a key
For an application or a developer, authentication is a PineMail key as a Bearer token: a project key (pm_live_) from the project's API keys page, or an account key (pm_acct_) from Buckets → Access keys. Make a key for the agent of its own, with the scopes it needs, and revoke it when the agent is gone. See Keys. The endpoint takes Streamable HTTP (one POST per request, no sessions) and serves clients on the 2025 revisions the same way.
Claude Code, with a key
Cursor, VS Code and other clients with a JSON config
Tools
Each tool is one call on the public API, made with your key, and returns the API's JSON. Scopes, send limits, sending-key locks and rate limits are the API's own; an agent can do nothing over MCP that its key cannot do over HTTP. describe_key is always listed and says which key is connected and which tools it has. get_limits is always listed too and gives the limits on what the key reaches, with what is used of each, so an agent can check before a large send.
| Scope | Tools |
|---|---|
emails:send | send_email (now or later, with a template or attachments), cancel_email |
emails:read | list_emails, get_email, list_suppressions, list_soft_bounces |
suppressions:write | add_suppressions, remove_suppression |
domains:read | list_domains, get_domain, check_domain_dns, list_senders |
domains:write | add_domain, verify_domain |
mailboxes:read | list_mailboxes, get_mailbox |
mailboxes:write | create_mailbox |
webhooks:read | list_webhooks |
templates:read | list_templates, get_template |
directory:read | list_directory |
mail:read | list_threads, get_thread, get_message, list_labels, read_attachment, get_assistant_access |
mail:draft | create_draft |
mail:send | send_from_mailbox, send_drafts, cancel_mailbox_message |
mail:organize | update_thread, update_threads |
calendar:read | list_calendar_events |
buckets:read | list_buckets, get_bucket, list_objects |
files:read | list_files, get_file, read_file |
Tools that read are marked read-only for the client, so it can run them without asking; send_email, add_domain, verify_domain and create_mailboxare marked as changes, and most clients ask before running them. An API error comes back as a tool error with the status, the reason and the field it concerns, the same text as the API's problem+json.
Mailbox mail
An assistant that reads an inbox, drafts replies or sends from a mailbox gets the Mailbox mail scopes: with a login, the ones the person ticks on the consent page; with a project key, the ones picked when the key is made, since Full access leaves them out. Scope by scope: only read (mail:read), also write drafts for a person to send (mail:draft), or send itself (mail:send); mail:organizelets it archive, mark read, star, snooze, label and trash threads. An account starts with drafts only: a connected assistant cannot send until the owner allows it under Account → Assistants and sending. Sending from a mailbox follows the mail app's rules: the message lands in Sent, counts against the account's monthly limit and the mailbox's daily cap, and waits out the mailbox's undo window;cancel_mailbox_message takes it back to Drafts meanwhile.
Received mail has a kind: mail, bounce (a delivery report), complaint (a spam report), auto_reply (out of office, a receipt) or challenge (a sender check that asks to confirm). list_threads filters on it and on the tags given at send, so an agent that sent a round of mail reads the replies written by people to that round with kind: mail and tag. A bounce or a reply names the sent message it answers in reply_to_message_id, and get_message on a sent message gives its delivery status, its bounces and its replies. send_drafts sends up to 100 drafts in one call, spaced by spacing_minutes from start_at.
Sending
send_email queues a message like POST /v1/emails: from a verified domain of the project, with text or html, and counts against the account's monthly send limit. An agent that retries passes the same idempotency_key, and the same email is returned instead of a second send. To let an agent send from one address only, give it a sending key locked to that domain and those From addresses; any other From answers with the allowed addresses.
What assistants reach
The account owner sets it under Account → Assistants, for every assistant on the account, connected with a login or through a key with the mail scopes. One switch turns assistants off for the whole account: sign-ins are refused on every route and on the MCP endpoint, the consent page allows nothing, and keys are refused on the mail routes and the document text routes, all with 403. With assistants on, the owner picks every mailbox or only some, the correspondents, and whether assistants read Drive. With "Internal only" an assistant reaches only threads where every address is the account's own (its verified domains and its mailboxes' addresses); with "Internal and listed", also the domains and addresses listed. A thread with one address outside is left out of lists and search and is 404 when read, as are its attachments; a draft or a send to an address outside is 403 and names it; calendar events with an organizer or attendee outside are left out. A mailbox kept from assistants is 404 on the mail tools.
get_assistant_access (GET /v1/mailboxes/{id}/assistant-access) tells an assistant what applies in a mailbox: the correspondents, the listed domains and addresses, and whether masking is on. It is read-only; only the owner changes it, on the account page.
Masking personal data
On by default, and switched under Account → Assistants. Before an assistant reads a thread, a calendar entry, an attachment or a Drive file, PineMail replaces names, email addresses (apart from the account's own mailboxes), phone numbers, Nordic identity numbers, organisation numbers, IBAN, card numbers and IP addresses with placeholders such as [EMAIL_K3F9Q2ZA] and [NAME_7XB2M4QP]. The analysis runs on PineMail's own server; names also come from the thread's senders and the mailbox's contacts. Masking covers what can be recognised; other personal data in a text passes as written.
The same value reads as the same placeholder everywhere in the account, so an assistant can tell people apart and reply to them. In create_draft and send_from_mailbox it uses the placeholders as it read them, and PineMail puts the real values back before anything is stored or sent. A placeholder PineMail cannot put back, in any field, is 422. HTML bodies are left out while masking is on (html_omitted: true), and every masked reply carries masking: "on" and masked, the count per kind.
When the masking cannot finish (the analyser down, its queue full, a wait over 25 seconds, or 60 for a document), the tool fails with 503 and Retry-After, and nothing of the content is in the answer. Every read and write is listed under Account → Assistants → Activity, without the content, for 90 days.
Seeing it in PineMail
The people reading the mail see what is hidden from assistants. A small mark on a thread in the list shows that personal data in it is masked, or that the thread is kept from assistants. Under the subject of an open thread, and in the file viewer for a Drive file, a line says what an assistant gets: for example "Hidden from assistants: 2 names, 1 identity number", with the values listed on Show. The line comes from the same masking an assistant's read gets, run as a preview with nothing stored or sent.
A thread or a file is checked the first time an assistant reads it; until then the line says "Not checked yet", and Check now checks it at once. The owner sets under Account → Assistants when the marks show (when an assistant or a key that reads mail or files is connected, which is the default; always; or never), and can have new mail and files checked when they arrive, so everything new has its mark from the start. That is off by default.
Documents
read_attachment gives the text of a mail attachment (ids from get_thread), and read_filethe text of a Drive file's current version (ids from list_files; a sign-in reaches the person's own Drive with files:read). Plain text, PDF, Word and spreadsheets are read, at most 10 MB, and the text ends after 200,000 characters. Other types are 422. The text is masked like mail.
Limits and errors
The endpoint answers 401 with a WWW-Authenticate header that names the OAuth resource metadata without a usable key or token, 403 when the API is turned off for the account, and 405 to GET and DELETE. A browser Origin other than pinemail.app is refused with 403. Tool calls share the API's rate limit per project or account, and a call over the limit is a tool error with 429 and the seconds to wait.