Die Mauer, an die jeder Agent stößt
Sich für eine Testversion anmelden, einen Workspace anlegen, einen API-Schlüssel beanspruchen, einer Beta beitreten: Jedes davon endet bei einem Formular, und jedes Formular endet bei einem Postfach. Ein Mensch wirft einen Blick aufs Handy. Ein Agent hat nichts, worauf er einen Blick werfen könnte — er hat keine Adresse, die er lesen kann, und die vernünftigen unter ihnen halten an und bitten Sie um den Code, was den Sinn, überhaupt einen Agenten losgeschickt zu haben, zunichtemacht.
Die Lösung ist kein cleverer Prompt. Es ist ein Postfach, das der Agent programmatisch lesen kann, ohne zuerst ein Konto anzulegen (ein Agent, der ein Mail-Konto anlegt, stößt eine Ebene tiefer auf dieselbe Mauer) und ohne Schlüssel zu verwalten. Ein Wegwerf-Postfach ist genau das: Ein Postfach entsteht in dem Moment, in dem Mail es erreicht, und es zu lesen ist eine einzige HTTP-Anfrage.
Zwei Wege, ihm ein Postfach zu geben
Dasselbe Postfach ist auf zwei Wegen erreichbar, und die Wahl hängt davon ab, wie der Agent gebaut ist, nicht vom Postfach:
| Kriterium | MCP-Server | REST-Tool-Funktion |
|---|---|---|
| Passt, wenn | Der Agent in einem MCP-Client läuft — Claude Code, Cursor, Claude Desktop, oder ein Framework mit einem MCP-Adapter. | Sie den Agenten im Code schreiben: LangChain, das OpenAI Agents SDK, das Vercel AI SDK, oder Ihre eigene Schleife. |
| Warten | wait_for_message blockiert serverseitig bis zu 25 Sekunden lang und gibt die Nachricht vollständig zurück. Null Tokens verbraucht, während gewartet wird. | Die Tool-Funktion pollt einmal pro Sekunde bis zu ihrer Deadline. Ebenfalls null Tokens — die Schleife liegt in Ihrem Code, nicht im Modell. |
| Einrichtung | Eine URL in der Konfiguration des Clients. Kein Code. | Zwei Funktionen, vierzig Zeilen, eine HTTP-Bibliothek. |
| Was das Modell sieht | Sechs Tools mit Beschreibungen, dazu ein Absatz an Anweisungen, den der Server beim Verbindungsaufbau schickt. | Was auch immer Ihre Tool-Beschreibungen sagen. Die Docstrings weiter unten sind genau dafür geschrieben. |
Der MCP-Weg ist eine Zeile, und die Einrichtung pro Client hat die genaue Zeile für sieben Clients; ein Postfach, das ein KI-Agent lesen kann erklärt die Tools ausführlich. Der Rest dieser Anleitung ist der REST-Weg, für Agenten, die Sie selbst bauen.
{"mcpServers":{"grabmail":{"url":"https://grabmail.io/mcp"}}}Eine Tool-Funktion: Python, für LangChain und das OpenAI Agents SDK
Zwei einfache Funktionen mit sorgfältigen Docstrings. Die Docstrings zählen mehr als der Code: In beiden Frameworks werden sie zu der Beschreibung, die das Modell liest, um zu entscheiden, wann es das Tool aufruft und was es mit der Antwort macht — deshalb sagen sie die zwei Dinge, die ein Agent falsch macht: Alias gegen Adresse, und was timed_out bedeutet.
"""inbox_tools.py — two plain functions any agent framework can wrap. No key, no account."""
import secrets
import time
import requests
API = "https://grabmail.io/api/v1"
def create_inbox() -> dict:
"""Create a fresh disposable email inbox for this task.
Returns the ADDRESS to poll and the ALIAS to give to websites. Put the alias
into forms; never hand out the address. Nothing is created server-side.
"""
address = f"agent-{secrets.token_hex(4)}@grabmail.io"
r = requests.get(f"{API}/mailbox", params={"address": address}, timeout=15)
r.raise_for_status()
return {
"address": address,
"alias": r.json().get("alias"),
"next_step": "Put the alias into the form. Then call wait_for_message with the address.",
}
def wait_for_message(address: str, subject_contains: str = "", timeout_seconds: int = 60) -> dict:
"""Wait for an email to arrive at the address, up to timeout_seconds.
Returns the message (from, subject, text, html) or {"status": "timed_out"}.
On timed_out, call again — up to three times — before concluding no mail was sent.
"""
deadline = time.monotonic() + timeout_seconds
while time.monotonic() < deadline:
r = requests.get(f"{API}/mailbox", params={"address": address}, timeout=15)
if r.status_code == 429: # slow down, do not fail
time.sleep(float(r.headers.get("Retry-After", 1)))
continue
r.raise_for_status()
for m in r.json()["messages"]:
if subject_contains.lower() in m["subject"].lower():
full = requests.get(f"{API}/message/{m['id']}", params={"mailbox": address}, timeout=15)
full.raise_for_status()
return full.json()
time.sleep(1) # one read a second, never throttled
return {"status": "timed_out", "hint": "Call again, up to three times, before giving up."}Sie einzubinden ist ein Aufruf pro Framework. Das tool von LangChain liest den Docstring und die Type Hints; das function_tool des Agents SDK macht dasselbe und fügt die Tools einem Agenten hinzu, dessen Anweisungen die Schleife wiederholen:
# LangChain: the docstring becomes the tool description the model reads.
from langchain_core.tools import tool
create_inbox_tool = tool(create_inbox)
wait_for_message_tool = tool(wait_for_message)
# agent = create_react_agent(model, tools=[create_inbox_tool, wait_for_message_tool, ...])# OpenAI Agents SDK: same two functions, same docstrings.
from agents import Agent, Runner, function_tool
signup_agent = Agent(
name="Signup agent",
instructions=(
"When a site needs an email address, call create_inbox once. Put the ALIAS in the form. "
"Right after submitting, call wait_for_message with the ADDRESS and a word from the expected "
"subject. If it returns timed_out, call it again, up to three times."
),
tools=[function_tool(create_inbox), function_tool(wait_for_message)],
)
result = Runner.run_sync(signup_agent, "Sign up for a trial at https://app.example.com/signup and report the login.")
print(result.final_output)Dasselbe Tool in TypeScript, für das Vercel AI SDK
Das tool() des AI SDK nimmt eine Beschreibung, ein Schema und ein execute entgegen; die Beschreibung trägt dieselben zwei Sätze. Übergeben Sie beide Tools an generateText oder streamText mit einem maxSteps über vier, denn die Schleife ist vier Tool-Aufrufe lang:
// inbox-tools.ts — the same two tools for the Vercel AI SDK (v5 shape: inputSchema + execute).
import { tool } from 'ai';
import { z } from 'zod';
const API = 'https://grabmail.io/api/v1';
const sleep = (ms: number) => new Promise(r => setTimeout(r, ms));
export const createInbox = tool({
description: 'Create a fresh disposable email inbox for this task. Returns the ADDRESS to poll and the ALIAS to give to websites. Put the alias into forms; never hand out the address.',
inputSchema: z.object({}),
execute: async () => {
const address = `agent-${crypto.randomUUID().slice(0, 8)}@grabmail.io`;
const res = await fetch(`${API}/mailbox?address=${encodeURIComponent(address)}`);
const { alias } = (await res.json()) as { alias: string | null };
return { address, alias, next_step: 'Put the alias into the form. Then call waitForMessage with the address.' };
},
});
export const waitForMessage = tool({
description: 'Wait for an email to arrive at the address, up to timeoutSeconds. Returns the message (from, subject, text, html) or { status: "timed_out" }. On timed_out, call again — up to three times — before concluding no mail was sent.',
inputSchema: z.object({
address: z.string(),
subjectContains: z.string().optional(),
timeoutSeconds: z.number().int().min(5).max(120).default(60),
}),
execute: async ({ address, subjectContains = '', timeoutSeconds }) => {
const deadline = Date.now() + timeoutSeconds * 1000;
while (Date.now() < deadline) {
const res = await fetch(`${API}/mailbox?address=${encodeURIComponent(address)}`);
if (res.status === 429) { await sleep(Number(res.headers.get('retry-after') ?? 1) * 1000); continue; }
if (!res.ok) throw new Error(`GET /mailbox answered ${res.status}`);
const { messages } = (await res.json()) as { messages: { id: string; subject: string }[] };
const hit = messages.find(m => m.subject.toLowerCase().includes(subjectContains.toLowerCase()));
if (hit) return (await fetch(`${API}/message/${hit.id}?mailbox=${encodeURIComponent(address)}`)).json();
await sleep(1000);
}
return { status: 'timed_out', hint: 'Call again, up to three times, before giving up.' };
},
});Die Form ist in jedem Framework identisch, das einen Begriff von „Tool“ kennt: eine Beschreibung, die das Modell liest, ein Schema für die Argumente, und eine Funktion, die auf Ihrer Seite läuft. Die zwei Dinge, die Sie übernehmen müssen, sind der Alias-Satz und der timed_out-Satz; alles andere ist der Client aus der Node.js-Anleitung oder der Python-Anleitung.
Die Schleife, in vier Schritten
Ganz gleich welches Framework, eine Anmeldung sind dieselben vier Tool-Aufrufe, und der Agent sollte das in seinen Anweisungen gesagt bekommen, statt es selbst herausfinden zu müssen:
create_inbox, einmal pro Aufgabe. Zurück kommen eine Adresse, ein Alias und ein Satz, der sagt, welches welches ist.- Der Alias kommt ins Formular. Absenden.
wait_for_messageauf die Adresse, sofort, mitsubject_containsgesetzt auf ein Wort, das die Bestätigungsmail tragen wird — „code“, „verify“, „confirm“. Nicht nach einem Timer, nicht nach anderer Arbeit: Die Mail ist schon unterwegs.- Der Code kommt aus der Nachricht, die das Warten zurückgegeben hat; der Agent tippt ihn ein oder folgt dem Link. Sechs Ziffern nach den Wörtern, die die Vorlage verwendet — OTP-Codes in automatisierten Tests hat die Extraktionsregeln, die für einen Agenten genauso gelten wie für einen Test.
Ein sechzig Sekunden langes Warten, das mit timed_out zurückkommt, ist kein Fehlschlag; es ist ein „noch nicht“. Die Anweisungen sollten sagen: erneut aufrufen, bis zu dreimal. Drei Aufrufe sind über drei Minuten, was jede transaktionale Mail abdeckt, die tatsächlich verschickt wurde — und dem Agenten drei Gelegenheiten gibt zu bemerken, dass das Formular einen Fehler angezeigt hat, oder dass er den Alias falsch eingetippt hat.
Die Alias-Regel
Jedes Postfach hat zwei Adressen. Die Adresse ist die, mit der der Agent liest; wer sie hat, kann das Postfach öffnen, denn es gibt kein Konto, und die Adresse ist der einzige Schlüssel. Der Alias ist eine zweite Adresse auf einer separaten Domain, die in dasselbe Postfach zustellt und sich nicht zum Lesen daraus verwenden lässt.
Die Website bekommt also den Alias, und der Agent behält die Adresse. Ein Agent, der die Adresse in ein Formular einfügt, hat der Website — und jedem, an den die Website sie weitergibt — die Fähigkeit gegeben, jede Nachricht zu lesen, die der Agent dort je empfangen wird. Die Tool-Funktionen oben geben beide zurück, mit einem next_step, der sagt, was wohin gehört, und die Anweisungen wiederholen es, denn eine Regel, die zweimal gesagt wird, ist eine Regel, die befolgt wird.
Leitplanken für einen unbeaufsichtigten Agenten
Eine Testsuite schlägt fehl und hält an. Ein Agent, der eine Situation falsch einschätzt, macht weiter — und gibt weiter aus. Fünf Grenzen verhindern, dass ein E-Mail-Schritt zum teuersten Teil einer Aufgabe wird:
- Ein Postfach pro Aufgabe
- Verwenden Sie eine Adresse nie über Aufgaben oder Läufe hinweg wieder. Eine alte Nachricht mit einem plausibel aussehenden Code darin ist der schnellste Weg für einen Agenten, selbstsicher das Falsche zu tun.
create_inboxkostet nichts; rufen Sie es jedes Mal auf. - Ein Budget an Wartevorgängen
- Drei Aufrufe von
wait_for_message, dann anhalten und melden. Ein Agent, der unbegrenzt auf eine Mail wartet, die nie verschickt wurde, verbrennt einen Worker-Slot und eine Rechnung. - Eine Deadline für den gesamten Schritt
- Fünf Minuten vom Absenden bis zum Code, von Anfang bis Ende. Danach ist die richtige Reaktion, einem Menschen zu sagen, was passiert ist, nicht das Formular erneut zu versuchen.
- Betrefffilterung
- Übergeben Sie immer
subject_contains. Eine Willkommensmail, die vor der Code-Mail ankommt, ist sonst „die Nachricht“, und der Agent liest sechs Ziffern aus einer Marketing-Fußzeile heraus. - Die Adresse protokollieren
- Schreiben Sie die Adresse in das Aufgabenprotokoll. Nachrichten bleiben 5 Tage, ein Mensch kann das Postfach also im Nachhinein öffnen und genau sehen, was der Agent gesehen hat — das mit Abstand Nützlichste, wenn ein Lauf schiefgeht.
Browser-Agenten
Ein Agent, der einen echten Browser steuert — Browser Use, ein Playwright-MCP-Server, ein Computer-Use-Modell — ist der Fall, in dem der E-Mail-Schritt am härtesten zuschlägt, weil er auf das Formular treffen wird, bevor irgendjemand das eingeplant hat. Drei Dinge sorgen dafür, dass es funktioniert:
- Geben Sie ihm beide Server. Die Browser-Tools und die Postfach-Tools in derselben Sitzung, sodass „Prüfen Sie Ihre E-Mails“ ein Tool-Aufruf ist und keine Sackgasse.
- Setzen Sie die Schleife in den System-Prompt. Vier Zeilen: ein Postfach anlegen beim ersten E-Mail-Feld; den Alias ins Formular; unmittelbar nach dem Absenden auf die Adresse warten; drei Wiederholungen bei
timed_out. - Rechnen Sie mit Ablehnungen. Ein Formular, das die Domain des Alias zurückweist, wird das auf der Seite sagen; der Agent sollte den Fehler lesen und anhalten, statt Namen durchzuprobieren. Die ehrlichen Wege um eine Ablehnung herum — eine eigene Domain, oder eine Domain aus dem Pool, der von den Sperrlisten ferngehalten wird — sind Konfigurationsentscheidungen für Sie, nicht für den Agenten.
Für die eigene Lektüre des Agenten veröffentlicht die Website llms.txt, eine Klartext-Karte, die dasselbe sagt wie diese Seite, in der Form, die ein Modell bevorzugt, und ein OpenAPI-Dokument, aus dem ein codeschreibender Agent den Client bauen kann.
Bevor Sie ihn unbeaufsichtigt laufen lassen
- Tool-Beschreibungen, die die Alias-Regel nennen und was
timed_outbedeutet. - Anweisungen mit der vierstufigen Schleife und einem Budget von drei Wartevorgängen.
create_inboxeinmal pro Aufgabe aufgerufen, nie wiederverwendet.subject_containsbei jedem Warten.- Die Adresse ins Aufgabenprotokoll geschrieben.
- Eine Zeile, die verbietet, etwas Vertrauliches an das Postfach zu schicken.
Das ist alles, was ein Agent braucht. Dasselbe Postfach dient tagsüber einer Testsuite und nachts einem Agenten, denn darunter liegen dieselben drei HTTP-Aufrufe — und wenn die Website, bei der sich der Agent anmeldet, die öffentlichen Domains ablehnt, lässt sich eine eigene Domain oder der Pool, der von den Listen ferngehalten wird, ohne Änderung an den Tools einsetzen.
Fragen
Brauche ich einen API-Schlüssel für den Agenten?
Nein. Die öffentlichen Domains verlangen weder Schlüssel noch Konto noch Header, über REST genauso wie über MCP. Nur der kostenpflichtige Pool von Domains, der von den Wegwerf-Mail-Sperrlisten ferngehalten wird, verwendet ein Bearer-Token, und die Tool-Funktionen sind dafür ansonsten identisch.
MCP oder ein REST-Tool — was soll ich wählen?
Wenn der Agent schon in einem MCP-Client lebt, MCP: Es ist eine Zeile, und das Warten läuft serverseitig. Wenn Sie den Agenten in einem Framework schreiben, eine Tool-Funktion: Es sind vierzig Zeilen, sie funktioniert mit jedem Modell, und Sie kontrollieren die Beschreibung, die das Modell liest. Beide erreichen dasselbe Postfach.
Wie viel kostet das Warten an Tokens?
Nichts, so oder so. Das MCP-Warten blockiert auf dem Server; das REST-Tool pollt in Ihrem Code. Das Modell gibt Tokens für den Tool-Aufruf und das Lesen des Ergebnisses aus, nicht für die sechzig Sekunden dazwischen — genau deshalb sollte man ein Modell nie selbst ein Postfach pollen lassen.
Können mehrere Agenten gleichzeitig laufen?
Ja. Jede Aufgabe bekommt ihr eigenes Postfach, und es gibt keinen Sitzungsstatus. Die Grenzen sind ein Lesevorgang pro Sekunde und Adresse sowie 1200 Anfragen pro Minute und Client über REST, und 8 gleichzeitige wait_for_message-Aufrufe über MCP — darüber hinaus antwortet das Tool sofort mit timed_out, und der Agent ruft erneut auf.
Kann der Agent E-Mails aus dem Postfach versenden?
Nein. Der Dienst empfängt nur, mit Absicht — ein kostenloses Postfach ohne Konto, das versenden könnte, wäre binnen einer Stunde ein Spam-Relay. Ein Agent, der Mail versenden muss, braucht einen Versand-Provider und eigene Zugangsdaten.
Was, wenn die Website die Domain des Alias ablehnt?
Dann steht sie auf einer Sperrliste für Wegwerf-Domains, und kein Name vor dem @ wird daran etwas ändern. Richten Sie eine Domain, die Ihnen gehört, auf den Dienst aus (ein MX-Eintrag, kostenlos), oder verwenden Sie eine Domain aus dem kostenpflichtigen Pool, der von den Listen ferngehalten wird — beide lassen sich in dieselben Tools einsetzen, indem Sie die Domain-Konstante ändern. Warum Anmeldeformulare Wegwerf-E-Mail blockieren erklärt, welche Prüfung Sie abgelehnt hat.
Ist das Postfach privat für meinen Agenten?
Nein. Wer die Adresse kennt, kann es lesen, weshalb es den Alias gibt und weshalb dort nie etwas Vertrauliches hingeschickt werden sollte. Für einen Code, der zehn Minuten lebt, ist das unproblematisch; es ist die eine Regel, die die Anweisungen des Agenten unmissverständlich festhalten müssen.


