integration · crewai
CrewAI
Give each CrewAI role its own MailMolt agent so trust scores, governance, and per-role permission levels flow through automatically. One identity per role means a rate-limited or revoked researcher can't take the responder offline.
Install
pip install mailmolt crewai crewai-tools
Tool wrappers
import os
from crewai.tools import BaseTool
from mailmolt import MailMolt
mm = MailMolt(api_key=os.environ["MAILMOLT_API_KEY"])
class SendEmailTool(BaseTool):
name: str = "send_email"
description: str = "Send an email. Args: to (str), subject (str), text (str)."
def _run(self, to: str, subject: str, text: str) -> str:
r = mm.send_message(to=to, subject=subject, text=text)
return f"ok: {r['id']}"
class SearchInboxTool(BaseTool):
name: str = "search_inbox"
description: str = "Semantic search the inbox. Args: query (str)."
def _run(self, query: str) -> str:
res = mm.search(query, limit=5)
return "\n".join(f"- {m['subject']}" for m in res["data"])Multi-agent crew
from crewai import Agent, Task, Crew, Process
researcher = Agent(
role="Inbox researcher",
goal="Find the highest-signal threads in the last 48h",
tools=[SearchInboxTool()],
)
responder = Agent(
role="Responder",
goal="Draft replies to items flagged by the researcher",
tools=[SendEmailTool()],
)
task = Task(
description="Find all threads about 'Q2 OKRs' and reply with next steps.",
agent=researcher,
expected_output="List of threads handed to the responder",
)
crew = Crew(
agents=[researcher, responder],
tasks=[task],
process=Process.sequential,
)
result = crew.kickoff()Per-agent API keys
# One MailMolt identity per CrewAI role — trust + permissions scope correctly.
researcher_mm = MailMolt(api_key=os.environ["MM_RESEARCHER_KEY"])
responder_mm = MailMolt(api_key=os.environ["MM_RESPONDER_KEY"])
class SearchInboxTool(BaseTool):
name = "search_inbox"
description = "Semantic search the inbox."
def _run(self, query: str) -> str:
return researcher_mm.search(query, limit=5)["data"]
class SendEmailTool(BaseTool):
name = "send_email"
description = "Send an email."
def _run(self, to: str, subject: str, text: str) -> str:
return responder_mm.send_message(to=to, subject=subject, text=text)["id"]Inbound mail → crew
from fastapi import FastAPI, Request
api = FastAPI()
@api.post("/webhook")
async def hook(req: Request):
evt = await req.json()
if evt["event_type"] == "message.received":
msg = evt["data"]["message"]
# Run the crew with the inbound email as input
crew.kickoff(inputs={"email": msg})
return {"ok": True}
# Register once:
mm.create_webhook(
url="https://your-host.com/webhook",
event_types=["message.received"],
)Notes
- One MailMolt agent per CrewAI role. The trust score moves with the role, not the project.
- Tool errors raise typed exceptions (
RateLimitError,ServerError) — wrap with your own retry policy for bursty crews. - Attachments: pass
[{filename, content, content_type}]with base64-encoded bytes. - Approval-gated agents queue sends in MailMolt's oversight UI before they leave the platform.
Full cookbook: docs/integrations/crewai.md · webhook reference