# Send & Receive Emails with OpenAI Agents SDK (/integrations/frameworks/openai-agents-sdk)

<!-- agent-signals: reading_time_min: 4 · est_tokens: 1619 · updated: 2026-09-06 -->
Related: [Send & Receive Emails with Claude Cowork](/integrations/frameworks/claude-cowork.md), [Send & Receive Emails with Claude Code](/integrations/frameworks/claude-code.md), [Send & Receive Emails with OpenAI Codex](/integrations/frameworks/codex.md), [Send & Receive Emails with OpenClaw](/integrations/frameworks/openclaw.md), [Send & Receive Emails with Grok](/integrations/frameworks/grok.md), [Send & Receive Emails with Manus](/integrations/frameworks/manus.md)



# Give an OpenAI Agents SDK agent an email inbox

The `agentmail-toolkit` package exposes AgentMail operations as the Agents SDK's own `FunctionTool` type. Use it when an agent built on the OpenAI Agents SDK needs to create inboxes, send email, and read and reply to threads.

## Do this

Python 3.11 or newer.

```bash
pip install agentmail-toolkit openai-agents
export AGENTMAIL_API_KEY="<API_KEY>"
export OPENAI_API_KEY="<OPENAI_API_KEY>"
```

```python
from agents import Agent, Runner
from agentmail_toolkit.openai import AgentMailToolkit

agent = Agent(
    name="Email Agent",
    instructions=(
        "You are an email agent with your own AgentMail inbox. "
        "You can create inboxes, send email, and read and reply to threads."
    ),
    tools=AgentMailToolkit().get_tools(),
)

result = Runner.run_sync(
    agent,
    "Create an inbox, then send an email from it to you@example.com with the "
    "subject 'Hello from my agent' and a one-line introduction. "
    "When finished, tell me the address of the new inbox.",
)
print(result.final_output)
```

## SDK

Install: `pip install agentmail-toolkit openai-agents`

* Build the toolkit: `AgentMailToolkit()` reads `AGENTMAIL_API_KEY` from the environment.
* Pass credentials another way: `AgentMailToolkit(client=AgentMail(api_key="..."))`.
* Get every tool as `FunctionTool` objects: `AgentMailToolkit().get_tools()`. The list goes straight into `Agent(tools=...)`.
* Get a subset: `AgentMailToolkit().get_tools(names=["list_threads", "get_thread", "reply_to_message"])`.
* Run the agent: `Runner.run_sync(agent, prompt)` in scripts, `await Runner.run(agent, prompt)` inside a running event loop.

Core SDK and CLI installs: /integrations/sdks-and-cli

## Facts

* `AGENTMAIL_API_KEY` authenticates the email tools. `OPENAI_API_KEY` authenticates the model calls the Agents SDK makes. Both must be set.
* Tools the page exercises: `create_inbox`, `send_message`, `list_threads`, `get_thread`, `reply_to_message`.
* A reply-only agent needs exactly `list_threads`, `get_thread`, and `reply_to_message`, passed via `get_tools(names=...)`. Scoped this way, the agent can read and reply to mail in inboxes that already exist, and that is all.
* The agent has no memory between runs. Each prompt must name the inbox to operate on.
* Mail moves in about two seconds each way. An agent that reports an empty inbox probably ran before the email arrived. Run it again.
* A prompt that names no username lets AgentMail generate an available one.
* Creating an inbox with a username owned by a different organization returns `403` with code `resource_taken`. A username already owned by the same organization returns `403` with code `already_exists`. Both list up to 3 available variants in `suggestions`.
* Creating an inbox past the plan's inbox limit returns `403` with code `limit_exceeded`.
* A failed tool call ends the run. `Runner.run_sync` raises `agents.exceptions.UserError` carrying the API's error message.
* The hosted MCP server is an alternative to this toolkit: /integrations/mcp-and-skills.

## Not supported

* A failed email tool call does not return its error to the model. The run ends with `UserError`, so an agent cannot retry a taken username within the same run. Prompt again with a different username, or leave the username out.
* `Runner.run_sync` does not work inside a running event loop, such as a notebook or an async app. It raises `RuntimeError`. Use `await Runner.run(agent, prompt)` there.
* Unknown names in `get_tools(names=...)` are dropped without an error, so the agent runs with fewer tools than intended. Print the returned tool names once to confirm the list.
* `AGENTMAIL_API_KEY` does not cover the model calls. Those need `OPENAI_API_KEY`.

## Errors

| Error                                     | Status                 | Cause                                                                                                            | Fix                                                                    |
| ----------------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `resource_taken`                          | 403                    | Requested inbox username owned by a different organization                                                       | Prompt again with a name from `suggestions`, or leave the username out |
| `already_exists`                          | 403                    | Requested inbox username already owned by the same organization                                                  | Prompt again with a name from `suggestions`, or leave the username out |
| `limit_exceeded`                          | 403                    | Inbox creation past the plan's inbox limit                                                                       | Run against an inbox that already exists                               |
| `agents.exceptions.UserError`             | carries the API status | A failed tool call ended the run, for example `Error running tool create_inbox: Inbox limit exceeded (HTTP 403)` | Fix the cause named in the message, then rerun                         |
| `openai.OpenAIError: Missing credentials` | none, Python exception | `OPENAI_API_KEY` unset. Fails before any email tool runs                                                         | Export `OPENAI_API_KEY`                                                |
| `RuntimeError`                            | none, Python exception | `Runner.run_sync` called inside a running event loop                                                             | Use `await Runner.run(agent, prompt)`                                  |

## Verify

```bash
python -c "
from agentmail_toolkit.openai import AgentMailToolkit
print([t.name for t in AgentMailToolkit().get_tools()])
"
```

Success prints the tool names, including `create_inbox`, `send_message`, `list_threads`, `get_thread`, and `reply_to_message`. This confirms the install, not the key. To confirm the key, run the send flow above and check that the email arrives.

## Related

* /advanced/webhooks - start a run when mail arrives instead of prompting by hand
* /advanced/safety - keep untrusted email content from steering the agent
* /integrations/mcp-and-skills - hosted MCP server alternative to the toolkit
