Using MailFlat with LangChain
MailFlatToolkit turns the Python SDK into LangChain tools, so an agent can open inboxes and read verification codes as part of its normal tool loop.
How it fits together
The toolkit is a thin shell over the same client you would call directly: every tool wraps one SDK method and returns a plain dict, and errors come back as {"error": "..."} instead of raising. That matters for an agent — a raised exception ends the run, a returned error is something the model can read and work around.
The tools
Six here, not seven: the toolkit has no delete_message, so a LangChain agent can drop a whole inbox but not quietly remove one message from it.
| Tool | Arguments | What it does |
|---|---|---|
| create_inbox | prefix? · label? · retention_hours? | Opens a real inbox and returns its address. |
| list_inboxes | — | Every inbox this API key can see. |
| read_messages | address | All messages in an inbox, newest first. |
| wait_for_otp | address · timeout? | Polls until a one-time code arrives, then returns it. |
| send_email | address · to · subject? · body? · html? | Sends a DKIM-signed email from the inbox. |
| delete_inbox | address | Deletes the inbox and every message in it. |
Install
langchain-core is an optional extra, so the plain package stays dependency-free for people who only want the client.
pip install "mailflat[langchain]"
Build the tools
get_tools() returns the six tools as LangChain BaseTool objects — ready for any agent that accepts a tool list.
import os
from mailflat.langchain import MailFlatToolkit
toolkit = MailFlatToolkit(api_key=os.environ["MAILFLAT_API_KEY"])
tools = toolkit.get_tools()
print([t.name for t in tools])
# ['create_inbox', 'list_inboxes', 'read_messages',
# 'wait_for_otp', 'send_email', 'delete_inbox']
Hand them to an agent
Nothing about MailFlat is special here: the tools go in the same list as the rest, and the model decides when an inbox is needed.
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import create_react_agent
llm = init_chat_model("claude-opus-5", model_provider="anthropic")
agent = create_react_agent(llm, tools)
result = agent.invoke({
"messages": [(
"user",
"Open an inbox labelled langchain-demo, tell me its address, "
"then wait up to 60 seconds for a one-time code and report it.",
)],
})
print(result["messages"][-1].content)
Give it fewer tools than you have
An agent that only reads mail has no reason to hold delete_inbox. Filtering the list is the whole mechanism — there is no separate permission model.
READ_ONLY = {"create_inbox", "read_messages", "wait_for_otp"}
tools = [t for t in toolkit.get_tools() if t.name in READ_ONLY]
Pair this with a short retention_hours so inboxes still disappear even though the agent cannot delete them.
Share one client between the toolkit and your own code
Pass a client in and the toolkit stops building its own. Useful when your code and the agent must talk to the same base URL, or when a test injects a fake.
from mailflat import MailFlat
from mailflat.langchain import MailFlatToolkit
mf = MailFlat(base_url="https://mail.example.com")
toolkit = MailFlatToolkit(client=mf)
inbox = mf.create(label="shared", retention_hours=2) # your code
agent_tools = toolkit.get_tools() # the agent's
Worth knowing
Tools return errors as data, not exceptions — so a model that asks for a code that never arrives sees {"error": "..."} and can decide to wait again. Log those returns; a silent retry loop is expensive.
wait_for_otp blocks the whole agent while it polls. Keep the timeout to what the mail actually needs (30-60 seconds) instead of the largest number that feels safe.
An encrypted inbox returns an error rather than a code, by design: the server cannot decrypt it. Create agent inboxes without encryption.
See also
OpenAI Agents SDK
There is no MailFlat package for the OpenAI Agents SDK and none is needed: attach the MCP server, or wrap the Python client in two function tools.
PythonThe official Python client wraps the REST API in two calls: open an inbox, wait for the code. Works in pytest, unittest, Robot Framework or a plain script.
One-time codesMailFlat pulls the verification code out of the message for you and hands it over as a field, so your test never runs a regex against an email body.