LangChain is the most popular framework for building LLM-powered applications. Its tool abstraction makes it straightforward to extend any agent with new capabilities, and email is no exception. With AgentSend, you can give your LangChain agent a real email address and the ability to send, receive, and manage threaded email conversations, all through a simple tool wrapper.

This guide walks through building a LangChain tool that wraps AgentSend's REST API, so your agent can autonomously compose and send emails, check its inbox, and reply to ongoing threads. The same approach works with LangGraph, LCEL chains, and any LangChain-compatible agent executor.

Why LangChain Agents Need Email

Most LangChain agents interact with APIs, databases, and search engines. But when an agent needs to communicate with a human outside your application, email is often the most practical channel. Consider these use cases:

Without a proper email tool, developers resort to hacks: piping output through SMTP libraries, hardcoding credentials, or building brittle email integrations from scratch. AgentSend eliminates this by providing a clean API purpose-built for agent communication.

Setting Up AgentSend

Before writing the LangChain tool, you need an AgentSend account and an API key. Sign up at agentsend.io, create an inbox, and grab your API key from the dashboard. The free tier includes 10 emails per day, enough to build and test your integration.

Install the required packages:

Terminal
pip install langchain langchain-openai requests

Building the LangChain Email Tool

LangChain's StructuredTool class lets you define tools with typed input schemas. Here is a complete tool that wraps AgentSend's send and receive endpoints:

langchain_agentsend.py
import os
import requests
from typing import Optional
from pydantic import BaseModel, Field
from langchain.tools import StructuredTool

AGENTSEND_API_KEY = os.environ["AGENTSEND_API_KEY"]
AGENTSEND_BASE = "https://agentsend.io"


class SendEmailInput(BaseModel):
    to: str = Field(description="Recipient email address")
    subject: str = Field(description="Email subject line")
    body: str = Field(description="Plain text email body")
    inbox_id: str = Field(description="AgentSend inbox ID")
    thread_id: Optional[str] = Field(
        default=None,
        description="Thread ID for replies (omit for new conversations)"
    )


def send_email(
    to: str,
    subject: str,
    body: str,
    inbox_id: str,
    thread_id: Optional[str] = None,
) -> str:
    """Send an email via AgentSend."""
    payload = {
        "inboxId": inbox_id,
        "to": to,
        "subject": subject,
        "text": body,
    }
    if thread_id:
        payload["threadId"] = thread_id

    resp = requests.post(
        f"{AGENTSEND_BASE}/messages",
        json=payload,
        headers={"Authorization": f"Bearer {AGENTSEND_API_KEY}"},
    )
    resp.raise_for_status()
    data = resp.json()
    return f"Email sent. Message ID: {data['id']}, Thread: {data['threadId']}"


class CheckInboxInput(BaseModel):
    inbox_id: str = Field(description="AgentSend inbox ID to check")


def check_inbox(inbox_id: str) -> str:
    """Check for new messages in an AgentSend inbox."""
    resp = requests.get(
        f"{AGENTSEND_BASE}/inboxes/{inbox_id}/messages",
        headers={"Authorization": f"Bearer {AGENTSEND_API_KEY}"},
    )
    resp.raise_for_status()
    messages = resp.json().get("messages", [])
    if not messages:
        return "No new messages."
    summary = []
    for msg in messages[:5]:
        summary.append(
            f"From: {msg['from']}, Subject: {msg['subject']}"
        )
    return "\n".join(summary)


# Create the LangChain tools
send_email_tool = StructuredTool.from_function(
    func=send_email,
    name="send_email",
    description="Send an email to a recipient via AgentSend",
    args_schema=SendEmailInput,
)

check_inbox_tool = StructuredTool.from_function(
    func=check_inbox,
    name="check_inbox",
    description="Check for new emails in an AgentSend inbox",
    args_schema=CheckInboxInput,
)

Using the Tool with a LangChain Agent

With the tools defined, you can attach them to any LangChain agent. Here is a complete example using the OpenAI functions agent:

agent.py
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain_core.prompts import ChatPromptTemplate

from langchain_agentsend import send_email_tool, check_inbox_tool

llm = ChatOpenAI(model="gpt-4o", temperature=0)
tools = [send_email_tool, check_inbox_tool]

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant with email capabilities. "
               "Your inbox ID is inbox_abc123."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

agent = create_openai_functions_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# The agent can now send email autonomously
result = executor.invoke({
    "input": "Send an email to team@example.com summarizing "
             "today's project status. Subject: Weekly Update"
})
print(result["output"])

When you run this, the agent will use its reasoning capabilities to compose an appropriate email body, then invoke the send_email tool to deliver it through AgentSend. The entire flow happens without human intervention.

Handling Incoming Email

AgentSend delivers incoming messages to your webhook endpoint in real time. You can set up a simple Flask or FastAPI server that receives the webhook payload and feeds it into your LangChain agent for processing:

webhook_handler.py
from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/webhook/email")
async def handle_email(request: Request):
    payload = await request.json()
    sender = payload["message"]["from"]
    subject = payload["message"]["subject"]
    body = payload["message"]["text"]
    thread_id = payload["message"]["threadId"]

    # Feed into your LangChain agent
    result = executor.invoke({
        "input": f"You received an email from {sender}. "
                 f"Subject: {subject}. Body: {body}. "
                 f"Thread ID: {thread_id}. Reply appropriately."
    })
    return {"status": "processed"}

This creates a closed loop: humans email your agent, your agent processes the message through LangChain, and replies through AgentSend. The thread ID ensures all replies stay in the same conversation thread in the sender's email client.

Tip: Store the thread_id alongside your agent's conversation memory. This lets the agent reference previous email exchanges when composing replies, maintaining context across multi-turn email conversations.

LangGraph Integration

If you are using LangGraph for stateful, multi-step workflows, the same tools work out of the box. Define email send and receive as nodes in your graph, and LangGraph's persistence layer will track conversation state across email exchanges. This is particularly powerful for workflows that span multiple email rounds, such as negotiation agents or iterative feedback loops.

Next Steps

Once your LangChain agent has email capabilities, you can extend the integration further:

Frequently Asked Questions

Can LangChain agents send email?

Yes. By wrapping AgentSend's REST API as a LangChain tool, any LangChain agent can send email, receive incoming messages via webhook, and manage threaded conversations. The tool integrates natively with LangChain's agent executor and works with any LLM backend.

How do I create a LangChain email tool?

Create a StructuredTool or BaseTool subclass that calls AgentSend's /messages endpoint. Define input parameters for recipient, subject, and body. The agent can then invoke the tool during its reasoning loop to compose and send email autonomously.

Does AgentSend work with LangGraph?

Yes. Since LangGraph builds on LangChain's tool abstraction, the same AgentSend tool works in LangGraph workflows. You can add email send and receive nodes to any graph, enabling multi-step workflows that include email communication.

Give Your LangChain Agent an Email Address

Free tier available. No credit card required. Build your LangChain email tool in under 5 minutes.

Start for Free →