Alt en MCP-klient gjør, kan et skript gjøre over vanlig HTTPS. Ett endepunkt, én API-nøkkel, JSON inn og JSON ut. Denne guiden dekker autentisering, de tre kallene du trenger, feil, nye forsøk, grenser og webhooks for ny e-post.
Hver forespørsel er en JSON-RPC 2.0 POST til https://mcpemails.com/api/mcp. Dette er samme endepunkt som claude.ai, ChatGPT og andre MCP-klienter bruker, med de samme verktøyene og de samme tillatelsene, så et skript og en chatassistent ser ett og samme produkt.
Content-Type: application/json og Accept: application/json. Svaret er ett JSON-objekt.Authorization-header.structuredContent-objekt, så du slipper å tolke prosa. De samme dataene ligger i content[0].text som en JSON-streng.mcpe_ etterfulgt av 64 heksadesimale tegn. Den vises én gang, når du oppretter den, og bare en hash lagres. Kopier den da; en mistet nøkkel kan ikke gjenopprettes, bare erstattes.Authorization: Bearer mcpe_.... Legg aldri en nøkkel i en URL eller en query-streng.Hver nøkkel har bare de tillatelsene du huker av når du oppretter den. Du kan endre dem senere med Rediger tilgang, og endringen gjelder fra neste kall uten å koble til på nytt.
| Omfang | Tillater |
|---|---|
read:email | Liste, lese og søke i meldinger, laste ned vedlegg, liste innbokser og mapper. |
search:email | Beholdt for eldre nøkler. Søk dekkes av read:email. |
send:email | Sende, svare og videresende. |
manage:drafts | Opprette, oppdatere og slette utkast. Å sende et utkast krever også send:email. |
manage:folders | Flytte, kopiere, flagge og arkivere meldinger; opprette, gi nytt navn til og slette mapper. |
delete:email | Slette og masseslette meldinger. |
manage:contacts | Søke etter kontakter i nylig e-post. |
schedule:email | Planlegge sendinger og håndtere planlagte e-poster. |
manage:automations | Opprette regler som kjører etter en tidsplan uten at noen følger med. |
Start med read:email og legg til et skriveomfang bare når arbeidsflyten trenger det. Et kall utenfor nøkkelens omfang avvises før vi kontakter e-postserveren din. Lesere i arbeidsområdet kan bare ha leseomfang.
En nøkkel når som standard alle innbokser i arbeidsområdet. For å låse den til noen av dem, åpne Rediger tilgang på nøkkelen og velg innboksene under Innbokstilgang. Begrensningen sjekkes på hvert kall, så en nøkkel låst til support-innboksen kan ikke lese økonomi-innboksen, uansett hva forespørselen sier.
Apper som folk kobler til selv, som claude.ai, ChatGPT og andre MCP-klienter, logger inn med OAuth i stedet for en nøkkel: dynamisk klientregistrering, autorisasjonskode med PKCE og en samtykkeskjerm der brukeren velger omfang og innbokser. Se OAuth-tilkobling. For dine egne skript, servere og arbeidsflyter er en API-nøkkel enklere.
MCP-klienter starter med initialize. Et skript kan hoppe over det, siden serveren ikke holder noen sesjon, men det er en billig måte å sjekke at nøkkelen virker og lese serverens instruksjoner.
curl -s https://mcpemails.com/api/mcp \
-H "Authorization: Bearer $MCPEMAILS_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"clientInfo": { "name": "my-agent", "version": "1.0" },
"capabilities": {}
}
}'tools/list returnerer alle verktøyene denne nøkkelen kan kalle, med beskrivelse, inndataskjema og utdataskjema. Les den ved oppstart i stedet for å hardkode verktøynavn eller argumenter: listen filtreres etter nøkkelens omfang, og verktøy får nye argumenter over tid.
curl -s https://mcpemails.com/api/mcp \
-H "Authorization: Bearer $MCPEMAILS_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'Kall et verktøy ved navn med argumentene. De fleste verktøy tar en action som bestemmer hva de gjør, som list, read eller search på email_read. Oppgi postboksen med inbox (adressen) eller inbox_id; inbox_list returnerer begge.
curl -s https://mcpemails.com/api/mcp \
-H "Authorization: Bearer $MCPEMAILS_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "email_read",
"arguments": { "action": "list", "inbox": "you@example.com", "unread": true, "limit": 20 }
}
}'Et vellykket resultat:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{ "type": "text", "text": "{\"messages\":[...],\"total\":42, ...}" }],
"structuredContent": {
"messages": [{ "id": "...", "subject": "...", "from": { "name": "...", "email": "..." } }],
"total": 42,
"total_is_estimate": false,
"has_more": true,
"next_offset": 20
}
}
}Verktøyreferansen beskriver hvert verktøy, og curl-guiden har flere eksempler.
Det finnes to typer. En forespørsel som ikke kunne kjøre i det hele tatt kommer tilbake som en JSON-RPC error med en HTTP-status. En forespørsel som nådde et verktøy og ble avvist av det kommer tilbake som et vanlig result med isError: true, slik at en AI-modell kan lese årsaken. Forgren på data.error_code eller _meta-koden, ikke på meldingsteksten.
| Svar | Når | Hva du gjør |
|---|---|---|
HTTP 401, -32001 | Manglende, feilformet, tilbakekalt eller utløpt nøkkel. | Rett Authorization-headeren eller opprett en ny nøkkel. Nye forsøk hjelper ikke. |
HTTP 403, -32004, insufficient_scope | Nøkkelen mangler et omfang denne verktøyhandlingen krever. data.required_scopes lister hva som ville tillatt den. | Legg til omfanget med Rediger tilgang, eller bruk en annen nøkkel. |
HTTP 429, -32003, rate_limit_exceeded | For mange forespørsler. data.window sier hvilket vindu som ble fullt. | Vent Retry-After sekunder (også i data.retry_after), og send så samme forespørsel på nytt. |
-32602 | Ukjent verktøynavn. data.available_tools lister navnene denne nøkkelen kan kalle. | Bruk et navn fra tools/list. |
isError: true, invalid_arguments | Argumentene besto ikke verktøyets skjema. Ingenting kjørte. Teksten navngir hvert ugyldige argument, og når et argumentnavn var gjettet, navngir den det som finnes. | Rett argumentene. De samme argumentene avvises på samme måte. |
isError: true, usage_limit_reached | Et Gratis-arbeidsområde har brukt opp månedens e-posthandlinger. | Vent til tilbakestillingsdatoen i _meta, eller oppgrader. Betalte planer har ingen månedlig grense. |
isError: true, annet | Verktøyet kjørte og feilet: melding ikke funnet, leverandøren avviste, ugyldig mottaker og så videre. | Les content[0].text. Den sier hva som skjedde og om noe ble sendt. |
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", ...
{
"jsonrpc": "2.0",
"id": 4,
"error": {
"code": -32004,
"message": "Insufficient scope: the 'send:email' scope is required to call email_compose.",
"data": { "error_code": "insufficient_scope", "required_scopes": ["send:email"], ... }
}
}HTTP/1.1 429 Too Many Requests
Retry-After: 12
{
"jsonrpc": "2.0",
"id": 5,
"error": {
"code": -32003,
"message": "Rate limit exceeded",
"data": { "error_code": "rate_limit_exceeded", "window": "per_minute", "retry_after": 12, ... }
}
}{
"jsonrpc": "2.0",
"id": 6,
"result": {
"isError": true,
"content": [{ "type": "text", "text": "Invalid arguments for email_read. The call was rejected before it ran, ..." }],
"_meta": {
"com.mcpemails/invalid_arguments": {
"error_code": "invalid_arguments",
"retryable": false,
"errors": [{ "path": "arguments.since", "message": "..." }]
}
}
}
}Hvert liste- og søkeresultat slutter med de samme fire feltene:
has_more: true når det finnes en side til. Bare has_more: false betyr at du har sett alt.next_offset: send den tilbake som offset, med alle andre argumenter uendret, for å få neste side. Den er null når has_more er false.total: antall treff, eller null når leverandøren ikke kan telle dem. Den motsier aldri siden du holder.total_is_estimate: true når total er et estimat eller et minimum og ikke et nøyaktig antall.Lange meldingstekster deles opp på samme måte: når body_truncated er true, les igjen med body_next_offset som body_offset.
En tilkobling som brytes etter en sending lar deg ikke vite om e-posten gikk ut. Send med en idempotency_key og prøv igjen med samme nøkkel: arbeidet kjører én gang.
curl -s https://mcpemails.com/api/mcp \
-H "Authorization: Bearer $MCPEMAILS_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "email_compose",
"arguments": {
"action": "send",
"inbox": "you@example.com",
"to": ["customer@example.com"],
"subject": "Your order has shipped",
"body": "Hi, your order is on its way.",
"idempotency_key": "order-1042-shipped"
}
}
}'tools/list viser idempotency_key i inndataskjemaet til hvert verktøy som tar den.idempotent_replay: true, den opprinnelige status og det opprinnelige utfallet i result, inkludert message_id du kan ha mistet.idempotency_key_conflict. Bruk en ny nøkkel for en ny operasjon.status: "processing". Prøv igjen om kort tid.status: "unknown". Sjekk Sendt før du sender igjen under en ny nøkkel.{
"idempotency_key": "order-1042-shipped",
"idempotent_replay": true,
"status": "succeeded",
"result": { "message_id": "...", "inbox_id": "...", "status": "sent" },
"message": "This logical request was already processed. ..."
}Enhver innboks kan holde tilbake alle sendinger til en person godkjenner dem. En sending fra skriptet ditt returnerer da en approval_id med status: "pending_approval" i stedet for å gå ut, og den går ut når noen godkjenner den i dashbordet. Dette fungerer på alle planer og er et godt utgangspunkt mens en ny automatisering beviser seg. Et nytt forsøk med samme idempotency_key rapporterer godkjenningen i stedet for å opprette en ny.
Hver plan har et tak per minutt for hele arbeidsområdet. En enkelt nøkkel kan bruke hele planens grense per minutt; flere nøkler deler den.
| Plan | Forespørsler per minutt | Webhooks |
|---|---|---|
| Free | 60 | Nei |
| Personal | 120 | Nei |
| Pro | 300 | Ja |
| Business | 1 000 | Ja |
tools/call-svar har RateLimit-Limit, RateLimit-Remaining og RateLimit-Reset (i sekunder) for det vinduet som er nærmest fullt, så en klient kan regulere tempoet før den treffer grensen.data.window.Retry-After i sekunder. Vent så lenge, og send så samme forespørsel på nytt.På Pro og Business kan MCPEmails sende en POST til din URL når e-post kommer inn i en innboks, så en arbeidsflyt starter på ny e-post i stedet for å polle. Opprett et endepunkt i dashbordet, velg innboksene og kopier signeringsnøkkelen, som vises én gang. URL-en må være HTTPS, på port 443 eller 8443. Bruk testknappen til å sende en signert ping-hendelse.
POST /your/webhook HTTP/1.1
Content-Type: application/json
MCPEmails-Event-Id: evt_...
MCPEmails-Event-Type: message.received
MCPEmails-Signature: t=1792843200,v1=5f2b...
{
"id": "evt_...",
"type": "message.received",
"created_at": "2026-10-24T09:20:00.000Z",
"workspace_id": "...",
"inbox_id": "...",
"folder": "INBOX",
"count": 1,
"message_ids": ["..."]
}type er message.received. message_ids lister de nye meldingene i innboksens INBOX-mappe, opptil 10 per hendelse; count er hvor mange som kom, og kan være flere.messages-liste med id, from og subject for hver melding.email_read (action: "read", inbox_id og en message_id) med en API-nøkkel. Nøkkelens omfang og innbokstilgang gjelder som vanlig.Hver levering har MCPEmails-Signature: t=<unix-sekunder>,v1=<hex>, der v1 er HMAC-SHA256 av tidsstempelet, et punktum og den rå forespørselskroppen, med endepunktets hemmelighet som nøkkel. Nøkkelen er hele hemmeligheten slik den vises, whsec_-prefikset inkludert. Beregn signaturen på nytt over den rå kroppen, sammenlign i konstant tid, og avvis et tidsstempel som er mer enn fem minutter gammelt.
import crypto from 'node:crypto';
// rawBody: the request body exactly as received, before JSON.parse.
export function verifyMcpemailsSignature(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(
String(header ?? '').split(',').map((part) => part.trim().split('=')),
);
const timestamp = Number(parts.t);
if (!Number.isFinite(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest();
const received = Buffer.from(parts.v1 ?? '', 'hex');
return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}MCPEmails-Event-Id til å ignorere en levering du allerede har behandlet. Et nytt forsøk har samme hendelses-id.POST, og registrer produksjons-URL-en som et webhook-endepunkt i MCPEmails-dashbordet.POST, URL https://mcpemails.com/api/mcp, autentisering Generic Credential Type → Header Auth med navn Authorization og verdi Bearer mcpe_....result.structuredContent.NODE_FUNCTION_ALLOW_BUILTIN=crypto.{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "email_read",
"arguments": {
"action": "read",
"inbox_id": "{{ $json.body.inbox_id }}",
"message_id": "{{ $json.body.message_ids[0] }}"
}
}
}For en AI Agent-node som leser og sender e-post selv, se n8n-guiden.
Legg til serveren med en nøkkel i en header. Det passer for hodeløse maskiner og CI, der det ikke finnes noen nettleser for OAuth-innloggingen:
claude mcp add --transport http mcpemails https://mcpemails.com/api/mcp \
--header "Authorization: Bearer $MCPEMAILS_KEY"Claude Code-guiden dekker OAuth-innloggingen og valget av omfang.
Lister alle uleste meldinger i én innboks, side for side, og venter ut en 429:
// node agent.mjs (Node 18 or later, MCPEMAILS_KEY in the environment)
const ENDPOINT = 'https://mcpemails.com/api/mcp';
let nextId = 1;
async function callTool(name, args) {
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MCPEMAILS_KEY}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({ jsonrpc: '2.0', id: nextId++, method: 'tools/call', params: { name, arguments: args } }),
});
if (res.status === 429) {
const wait = Number(res.headers.get('Retry-After') ?? 1);
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
return callTool(name, args);
}
const reply = await res.json();
if (reply.error) throw new Error(`${reply.error.code}: ${reply.error.message}`);
if (reply.result.isError) throw new Error(reply.result.content[0].text);
return reply.result.structuredContent;
}
const inbox = 'you@example.com';
let offset = 0;
do {
const page = await callTool('email_read', { action: 'list', inbox, unread: true, limit: 50, offset });
for (const m of page.messages) console.log(m.id, m.from?.email, m.subject);
offset = page.has_more ? page.next_offset : null;
} while (offset !== null);OpenClaw logger inn med OAuth som standard; OpenClaw-guiden går gjennom det. For å bruke en avgrenset nøkkel i stedet, legg den i serveroppføringens headers-map og la auth stå tom, fordi OpenClaw ignorerer en statisk Authorization-header på en oppføring satt til OAuth.
{
"mcp": {
"servers": {
"mcpemails": {
"url": "https://mcpemails.com/api/mcp",
"transport": "streamable-http",
"headers": { "Authorization": "Bearer mcpe_YOUR_KEY_HERE" }
}
}
}
}Opprett en nøkkel, kall tools/list, og se din egen e-post komme tilbake som JSON.