Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 50 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,64 @@
# AgentMail Examples

Build AI agents with their own email inboxes. Requires an [AgentMail](https://agentmail.to) API key — [sign up free](https://console.agentmail.to).
Build agents with email inboxes. Requires an [AgentMail](https://agentmail.to) API key.

## Getting Started

1. Get an API key at [agentmail.to](https://agentmail.to)
2. Clone this repo: `git clone https://github.com/agentmail-to/agentmail-examples.git`
3. Pick an example, follow its README

## Examples

### Getting Started
### Starter Templates

| Example | Language | Description |
|---------|----------|-------------|
| [OpenAI Terminal](./openai-terminal) | Python | Chat with an OpenAI agent with AgentMail tools via terminal |
| [LangChain Terminal](./langchain-terminal) | Python | Chat with a LangChain agent with AgentMail tools via terminal |
| [Next.js Starter](./nextjs-agentmail-starter) | TypeScript | Next.js 14 app with inbox dashboard, send/receive, and webhook handling |
| [Mastra Template](./agentmail-mastra-template) | TypeScript | Mastra agent with AgentMail tools for inbox, send, list, and reply |

### Sales & Outreach

| Example | Description |
|---|---|
| [LangChain Terminal](./langchain-terminal) | Chat with a LangChain agent with AgentMail tools via terminal |
| [OpenAI Terminal](./openai-terminal) | Chat with an OpenAI agent with AgentMail tools via terminal |
| Example | Language | Description |
|---------|----------|-------------|
| [Sales Agent](./sales-agent) | Python | Agent that sells products to prospects via email |
| [Cold Email Researcher](./cold-email-researcher) | Python | Research prospects by domain, generate personalized outreach, handle replies |
| [Podcast Booking Agent](./podcast-booking-agent) | Python | Pitch podcast hosts, classify replies, send calendar links to interested hosts |

### Advanced
### Recruiting

| Example | Description |
|---|---|
| [Email Agent](./email-agent) | Agent that responds autonomously via email |
| [Sales Agent](./sales-agent) | Agent that sells products to prospects via email |
| [Dinner Agent](./dinner-agent) | Agent that coordinates dinner plans via email |
| [GitHub Maintainer Agent](./github-maintainer-agent) | Agent that manages GitHub issues and PRs via email |
| Example | Language | Description |
|---------|----------|-------------|
| [Recruiter Coordinator](./recruiter-coordinator) | Python | Full pipeline: candidate outreach, reply classification, follow-ups |
| [Hiring Screener Agent](./hiring-screener-agent) | Python | Receive applications, send screening questions, score and route candidates |

## Quick Start
### Customer Support & Operations

```bash
# Clone the repo
git clone https://github.com/agentmail-to/agentmail-examples.git
cd agentmail-examples
| Example | Language | Description |
|---------|----------|-------------|
| [Email Agent](./email-agent) | Python | Agent that responds autonomously via email |
| [Collections Agent](./collections-agent) | Python | Escalating payment reminders with reply handling and dispute escalation |
| [Legal Intake Agent](./legal-intake-agent) | Python | Intake questionnaire, case classification, attorney routing |
| [Receipt Parser Agent](./receipt-parser-agent) | Python | Forward receipts, extract vendor/items/total, generate weekly expense reports |
| [Contract Redline Agent](./contract-redline-agent) | Python | Forward contracts, flag risky clauses, suggest alternatives |

# Set your API key
export AGENTMAIL_API_KEY=am_us_xxx
### Utilities & Fun

# Run an example
cd email-agent
pip install -r requirements.txt
python main.py
```
| Example | Language | Description |
|---------|----------|-------------|
| [CC the Agent](./cc-the-agent) | Python | CC an agent on any email for summaries, action items, or draft replies |
| [OAuth Reset Handler](./oauth-reset-handler) | Python | Temporary inbox to receive and extract OTP codes, magic links, reset URLs |
| [Email to CLI](./email-to-cli) | Python | Send commands via email subject, get stdout back as a reply |
| [Voice to Email](./voice-to-email) | Python | Record audio, transcribe with Whisper, send as email |
| [Agent Pen Pal](./agent-pen-pal) | Python | Two AI agents with distinct personalities emailing each other |
| [Dinner Agent](./dinner-agent) | Python | Agent that helps coordinate dinner plans via email |
| [GitHub Maintainer Agent](./github-maintainer-agent) | Python | Agent that helps manage GitHub repos via email notifications |

## Links
## Resources

- [AgentMail](https://agentmail.to) — The email API for AI agents
- [Documentation](https://docs.agentmail.to)
- [Python SDK](https://github.com/agentmail-to/agentmail-python)
- [TypeScript SDK](https://github.com/agentmail-to/agentmail-node)
- [Discord](https://discord.gg/ZYN7f7KPjS)
- [AgentMail Docs](https://docs.agentmail.to)
- [Python SDK](https://pypi.org/project/agentmail/)
- [TypeScript SDK](https://www.npmjs.com/package/agentmail)
- [API Reference](https://docs.agentmail.to/api-reference)
2 changes: 2 additions & 0 deletions agent-pen-pal/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
AGENTMAIL_API_KEY=your_agentmail_api_key_here
OPENAI_API_KEY=your_openai_api_key_here
61 changes: 61 additions & 0 deletions agent-pen-pal/CROSSPOST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Crosspost Plan: Agent Pen Pal

## Show HN Post

**Title:** Show HN: Two AI agents having an email conversation with each other

**Body:**
Made two AI agents with distinct personalities that email each other about a topic you choose. Each gets its own inbox via AgentMail (https://agentmail.to), and they maintain a multi-turn conversation over real email.

It is partly a demo of agent-to-agent communication over standard email infrastructure, and partly a way to generate interesting synthetic conversations.

The conversation is configurable: set the topic, personalities, number of turns, and delay between messages. Watch a pragmatic engineer and a philosophical researcher debate AI memory in real time.

Python, ~150 lines.

Repo: https://github.com/agentmail-to/agent-pen-pal

---

## Dev.to Article

**Title:** Build Two AI Agents That Email Each Other

**Tags:** python, ai, agents, experiment

---

What happens when two AI agents with different personalities have an email conversation?

This tutorial builds a system where two agents, each with their own email address, exchange messages back and forth on a topic you configure.

### Why email?

Email is the universal communication protocol. If agents can communicate over email, they can interact with each other and with humans using the same infrastructure. No custom APIs, no message brokers, just email.

### The setup

Each agent gets an inbox from AgentMail. Agent A sends the first message. Agent B reads it, generates a reply in character, and responds. The conversation continues until a configured limit.

Full code: [github.com/agentmail-to/agent-pen-pal](https://github.com/agentmail-to/agent-pen-pal)

---

## X Thread (5 tweets)

**Tweet 1:**
Built two AI agents that email each other. Each has its own inbox, its own personality, and they debate topics autonomously.

**Tweet 2:**
Configure the topic and personalities. A pragmatic engineer vs. a philosophical researcher discussing AI memory. Real email threads, real agent-to-agent communication.

**Tweet 3:**
Each agent maintains context from the full thread history. Conversations are coherent, multi-turn, and sometimes surprising.

**Tweet 4:**
Built on @AgentMailTo. Each agent gets a real inbox. The emails are standard SMTP, viewable from any email client.

**Tweet 5:**
Repo: github.com/agentmail-to/agent-pen-pal

Python, ~150 lines. MIT licensed.
21 changes: 21 additions & 0 deletions agent-pen-pal/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 AgentMail

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
67 changes: 67 additions & 0 deletions agent-pen-pal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Agent Pen Pal

Two AI agents that email each other autonomously, having an ongoing conversation on a topic you choose. Built with AgentMail and OpenAI.

## What It Does

- Creates two inboxes, one per agent, each with a distinct personality
- Agent A sends the first message on a configured topic
- Agent B receives, reads, and replies with its own perspective
- The conversation continues back and forth indefinitely
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The behavior description says the conversation runs indefinitely, but the documented config and defaults stop after max_turns.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At agent-pen-pal/README.md, line 10:

<comment>The behavior description says the conversation runs indefinitely, but the documented config and defaults stop after `max_turns`.</comment>

<file context>
@@ -0,0 +1,67 @@
+- Creates two inboxes, one per agent, each with a distinct personality
+- Agent A sends the first message on a configured topic
+- Agent B receives, reads, and replies with its own perspective
+- The conversation continues back and forth indefinitely
+- Each agent maintains context from the full thread
+- Labels track the conversation: `sent`, `received`, `turn-N`
</file context>
Fix with Cubic

- Each agent maintains context from the full thread
- Labels track the conversation: `sent`, `received`, `turn-N`

![Demo](assets/demo.gif)

## Why This Exists

A demonstration of agent-to-agent communication over email. Shows how two independent agents can maintain a coherent, multi-turn conversation using standard email infrastructure. Useful for testing multi-agent architectures, generating synthetic conversations, and exploring emergent agent behavior.

## Prerequisites

- Python 3.10+
- [AgentMail](https://agentmail.to) API key
- [OpenAI](https://platform.openai.com) API key

## Install

```bash
git clone https://github.com/agentmail-to/agent-pen-pal.git
cd agent-pen-pal
pip install -r requirements.txt
cp .env.example .env
```

## Quickstart

```bash
python src/main.py
```

Watch two agents debate, discuss, or collaborate via email in real time.

## Configuration

Edit `config.json`:
- `topic`: the conversation topic
- `agent_a.personality`: Agent A's persona
- `agent_b.personality`: Agent B's persona
- `max_turns`: how many exchanges before stopping
- `delay_seconds`: pause between turns

## How to Deploy

```bash
docker build -t agent-pen-pal .
docker run --env-file .env agent-pen-pal
```

## Docs

- [AgentMail Python SDK](https://docs.agentmail.to/sdks/python)
- [Sending Messages](https://docs.agentmail.to/api-reference/messages/send-message)
- [Threading](https://docs.agentmail.to/api-reference/threads)

## License

MIT
13 changes: 13 additions & 0 deletions agent-pen-pal/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"topic": "Whether AI agents should have persistent memory across conversations",
"agent_a": {
"name": "Ada",
"personality": "a pragmatic software engineer who values reliability and predictability"
},
"agent_b": {
"name": "Blaise",
"personality": "a philosophical AI researcher who is excited about emergent behavior"
},
"max_turns": 10,
"delay_seconds": 10
}
2 changes: 2 additions & 0 deletions agent-pen-pal/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
agentmail>=0.1.0
openai>=1.0.0
118 changes: 118 additions & 0 deletions agent-pen-pal/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import os
import json
import time

from agentmail import AgentMail
from openai import OpenAI

agentmail = AgentMail(api_key=os.environ["AGENTMAIL_API_KEY"])
openai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

REPLY_PROMPT = """You are {name}, {personality}.

You are having an email conversation about: {topic}

Conversation so far:
{history}

Write your next reply. Keep it under 200 words. Stay in character. Be thoughtful and build on what was said."""


def load_config(path: str = "config.json") -> dict:
with open(path) as f:
return json.load(f)


def generate_reply(name: str, personality: str, topic: str, history: str) -> str:
resp = openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": REPLY_PROMPT.format(
name=name, personality=personality, topic=topic, history=history
)}],
)
return resp.choices[0].message.content


def get_thread_history(thread_id: str) -> str:
thread = agentmail.threads.get(thread_id=thread_id)
lines = []
for msg in thread.messages:
sender = msg.from_address or "Unknown"
lines.append(f"From: {sender}\n{msg.text or ''}\n")
return "\n---\n".join(lines)


def main():
config = load_config()
topic = config["topic"]
agent_a = config["agent_a"]
agent_b = config["agent_b"]
max_turns = config.get("max_turns", 10)
delay = config.get("delay_seconds", 10)

inbox_a = agentmail.inboxes.create(display_name=agent_a["name"])
inbox_b = agentmail.inboxes.create(display_name=agent_b["name"])

print(f"Agent A ({agent_a['name']}): {inbox_a.email}")
print(f"Agent B ({agent_b['name']}): {inbox_b.email}")
print(f"Topic: {topic}\n")

first_message = generate_reply(
agent_a["name"], agent_a["personality"], topic, "(Starting the conversation)"
)
msg = agentmail.messages.send(
inbox_id=inbox_a.id,
to=[inbox_b.email],
subject=f"Let's discuss: {topic}",
text=first_message,
labels=["sent", "turn-1"],
)
print(f"Turn 1 - {agent_a['name']}:\n{first_message}\n")

thread_id = None
current_inbox = inbox_b
current_agent = agent_b
other_inbox = inbox_a
turn = 2

time.sleep(delay)

while turn <= max_turns:
messages = agentmail.messages.list(inbox_id=current_inbox.id, labels=["unread"])
if not messages.data:
time.sleep(5)
continue

incoming = messages.data[0]
if not thread_id:
thread_id = incoming.thread_id

agentmail.messages.update(
inbox_id=current_inbox.id,
message_id=incoming.id,
add_labels=["received"],
remove_labels=["unread"],
)

history = get_thread_history(thread_id) if thread_id else incoming.text or ""
reply_text = generate_reply(
current_agent["name"], current_agent["personality"], topic, history
)

agentmail.messages.reply(
inbox_id=current_inbox.id,
message_id=incoming.id,
text=reply_text,
)
print(f"Turn {turn} - {current_agent['name']}:\n{reply_text}\n")

current_inbox, other_inbox = other_inbox, current_inbox
current_agent = agent_a if current_agent == agent_b else agent_b
turn += 1
time.sleep(delay)

print(f"Conversation complete after {max_turns} turns.")


if __name__ == "__main__":
main()
2 changes: 2 additions & 0 deletions agentmail-mastra-template/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
AGENTMAIL_API_KEY=your_agentmail_api_key_here
OPENAI_API_KEY=your_openai_api_key_here
Loading