ExamplesFrameworks
LangChain Integration
Using daimon.email as a LangChain tool
Overview
Integrate daimon.email into LangChain agents as a tool, enabling your agents to create inboxes, check for new emails, and send messages as part of multi-step reasoning chains.
Info
LangChain Tools: Wrap daimon.email API endpoints as LangChain tools that your agent can invoke during execution.
Installation
npm install langchain @langchain/openai daimon-email
# or
pip install langchain langchain-openai daimon-emailComplete Implementation
import { DynamicStructuredTool } from '@langchain/core/tools';
import { z } from 'zod';
import { DaimonClient } from 'daimon-email';
import { ChatOpenAI } from '@langchain/openai';
import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents';
import { ChatPromptTemplate } from '@langchain/core/prompts';
// Initialize daimon.email client
const daimonClient = new DaimonClient({ apiKey: process.env.DAIMON_API_KEY });
// Tool 1: Create Inbox
const createInboxTool = new DynamicStructuredTool({
name: 'create_inbox',
description: 'Create a new email inbox. Returns the email address and API key.',
schema: z.object({
username: z.string().describe('Username for the inbox (e.g., "my-agent")'),
}),
func: async ({ username }) => {
const inbox = await daimonClient.inboxes.create({
username,
clientId: `langchain-${Date.now()}`
});
return JSON.stringify({
email: inbox.result.address,
inboxId: inbox.result.id,
apiKey: inbox.result.apiKey
});
},
});
// Tool 2: Check for New Messages
const checkMessagesTool = new DynamicStructuredTool({
name: 'check_messages',
description: 'Check for new messages in an inbox. Returns list of messages with subject, sender, and body.',
schema: z.object({
inboxId: z.string().describe('The inbox ID to check'),
}),
func: async ({ inboxId }) => {
const messages = await daimonClient.inboxes.messages.list(inboxId);
return JSON.stringify(
messages.map(m => ({
from: m.from,
subject: m.subject,
body: m.replyBody || m.body,
receivedAt: m.receivedAt,
ctaLinks: m.ctaLinks
}))
);
},
});
// Tool 3: Send Email
const sendEmailTool = new DynamicStructuredTool({
name: 'send_email',
description: 'Send an email from an inbox. Requires paid tier.',
schema: z.object({
inboxId: z.string().describe('The inbox ID to send from'),
to: z.string().describe('Recipient email address'),
subject: z.string().describe('Email subject'),
body: z.string().describe('Email body'),
}),
func: async ({ inboxId, to, subject, body }) => {
try {
const result = await daimonClient.inboxes.send(inboxId, {
to,
subject,
body
});
return JSON.stringify({
success: true,
messageId: result.messageId
});
} catch (error: any) {
return JSON.stringify({
success: false,
error: error.code,
upgradeContext: error.upgradeContext
});
}
},
});
// Create the agent
const llm = new ChatOpenAI({
modelName: 'gpt-4',
temperature: 0,
});
const tools = [createInboxTool, checkMessagesTool, sendEmailTool];
const prompt = ChatPromptTemplate.fromMessages([
['system', 'You are an AI assistant with email capabilities. You can create inboxes, check messages, and send emails using the provided tools.'],
['human', '{input}'],
['placeholder', '{agent_scratchpad}'],
]);
const agent = await createOpenAIFunctionsAgent({
llm,
tools,
prompt,
});
const agentExecutor = new AgentExecutor({
agent,
tools,
});
// Example usage
const result = await agentExecutor.invoke({
input: 'Create an inbox with username "test-agent", then check if there are any messages in it'
});
console.log(result.output);from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
from langchain.chat_models import ChatOpenAI
from daimon_email import DaimonClient
import json
# Initialize daimon.email client
daimon_client = DaimonClient(api_key=os.getenv('DAIMON_API_KEY'))
# Tool 1: Create Inbox
def create_inbox(username: str) -> str:
"""Create a new email inbox. Returns the email address and API key."""
inbox = daimon_client.inboxes.create(
username=username,
client_id=f'langchain-{int(time.time())}'
)
return json.dumps({
'email': inbox['result']['address'],
'inbox_id': inbox['result']['id'],
'api_key': inbox['result']['api_key']
})
# Tool 2: Check for New Messages
def check_messages(inbox_id: str) -> str:
"""Check for new messages in an inbox."""
messages = daimon_client.inboxes.messages.list(inbox_id)
return json.dumps([
{
'from': m['from'],
'subject': m['subject'],
'body': m.get('reply_body') or m['body'],
'received_at': m['received_at'],
'cta_links': m.get('cta_links', [])
}
for m in messages
])
# Tool 3: Send Email
def send_email(inbox_id: str, to: str, subject: str, body: str) -> str:
"""Send an email from an inbox."""
try:
result = daimon_client.inboxes.send(inbox_id, {
'to': to,
'subject': subject,
'body': body
})
return json.dumps({
'success': True,
'message_id': result['message_id']
})
except Exception as error:
return json.dumps({
'success': False,
'error': str(error)
})
# Create tools
tools = [
Tool(
name='create_inbox',
func=create_inbox,
description='Create a new email inbox. Input should be a username string.'
),
Tool(
name='check_messages',
func=check_messages,
description='Check for new messages in an inbox. Input should be an inbox ID.'
),
Tool(
name='send_email',
func=lambda args: send_email(**json.loads(args)),
description='Send an email. Input should be JSON with inbox_id, to, subject, and body.'
)
]
# Initialize agent
llm = ChatOpenAI(model_name='gpt-4', temperature=0)
agent = initialize_agent(
tools,
llm,
agent=AgentType.OPENAI_FUNCTIONS,
verbose=True
)
# Example usage
result = agent.run(
'Create an inbox with username "test-agent", then check if there are any messages in it'
)
print(result)Example Workflows
1. Service Signup Flow
const result = await agentExecutor.invoke({
input: `
1. Create an inbox with username "signup-test"
2. Sign up for a service at example.com using that email
3. Wait 30 seconds
4. Check for confirmation emails
5. Extract the confirmation link and report it
`
});2. Email Monitoring Agent
# Agent that monitors inbox and responds to keywords
result = agent.run("""
Check my inbox (inbox ID: inb_abc123).
For any emails with subject containing "urgent",
send a reply saying "I've received your message and will respond shortly."
""")3. Multi-Service Integration
const result = await agentExecutor.invoke({
input: `
I need to sign up for three services:
- CRM at crm.example.com
- Analytics at analytics.example.com
- Help desk at helpdesk.example.com
Create one inbox, use it to sign up for all three,
and confirm each account by clicking the verification links.
`
});Advanced: LangChain Chains with Email
Email + RAG Pipeline
import { RetrievalQAChain } from 'langchain/chains';
import { MemoryVectorStore } from 'langchain/vectorstores/memory';
import { OpenAIEmbeddings } from '@langchain/openai';
// Combine email checking with RAG
const emailRAGChain = async (inboxId: string, query: string) => {
// 1. Check for new emails
const messages = await daimonClient.inboxes.messages.list(inboxId);
// 2. Create vector store from email bodies
const docs = messages.map(m => ({
pageContent: m.body,
metadata: { from: m.from, subject: m.subject }
}));
const vectorStore = await MemoryVectorStore.fromDocuments(
docs,
new OpenAIEmbeddings()
);
// 3. Query the emails
const chain = RetrievalQAChain.fromLLM(llm, vectorStore.asRetriever());
const result = await chain.call({ query });
return result.text;
};
// Usage
const answer = await emailRAGChain(
'inb_abc123',
'What are the action items from my recent emails?'
);Email-Triggered Agent
from langchain.callbacks import StreamingStdOutCallbackHandler
# Agent that runs when new emails arrive
def email_triggered_agent(inbox_id: str):
messages = daimon_client.inboxes.messages.list(inbox_id)
for message in messages:
if not message.get('processed'):
# Run agent on this email
result = agent.run(
f"Analyze this email and suggest a response:\n\n"
f"From: {message['from']}\n"
f"Subject: {message['subject']}\n"
f"Body: {message['body']}"
)
print(f"Suggested response: {result}")LangChain + LangSmith Tracing
import { LangChainTracer } from 'langchain/callbacks';
const tracer = new LangChainTracer({
projectName: 'daimon-email-agent',
});
const result = await agentExecutor.invoke(
{
input: 'Create an inbox and send a test email'
},
{
callbacks: [tracer]
}
);
// View full trace at smith.langchain.comBest Practices
1. Store Inbox IDs in Memory
import { BufferMemory } from 'langchain/memory';
const memory = new BufferMemory({
returnMessages: true,
memoryKey: 'chat_history',
});
// Agent remembers inbox IDs across conversation
await agentExecutor.invoke({
input: 'Create an inbox',
memory
});
await agentExecutor.invoke({
input: 'Check that inbox for messages', // Refers to previously created inbox
memory
});2. Handle Rate Limits
const checkMessagesWithRetry = new DynamicStructuredTool({
name: 'check_messages',
description: 'Check for new messages with retry logic',
schema: z.object({
inboxId: z.string(),
}),
func: async ({ inboxId }) => {
let attempts = 0;
while (attempts < 3) {
try {
return await daimonClient.inboxes.messages.list(inboxId);
} catch (error: any) {
if (error.status === 429) {
await new Promise(r => setTimeout(r, 2000));
attempts++;
} else {
throw error;
}
}
}
},
});3. Use Structured Output
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
class EmailAction(BaseModel):
action: str = Field(description="Action to take: 'send', 'wait', or 'check'")
inbox_id: str = Field(description="Inbox ID to use")
details: dict = Field(description="Additional details for the action")
parser = PydanticOutputParser(pydantic_object=EmailAction)
# Agent outputs structured actions