LOOMAL
CrewAIPython

Per-agent email identities
for CrewAI crews.

CrewAI agents play roles — researcher, writer, sales, support. Each role deserves its own identity. Loomal mints one email + vault per agent, so the sales agent's address differs from the support agent's, and revoking one doesn't touch the others.

Per-role identityCrew-wide audit trailEmail handoffs between agentsVault per agentMCP tool integration

Prerequisites

  • Loomal account (free at console.loomal.ai)
  • Python 3.10+
  • crewai and crewai-tools installed
  • An LLM provider key

CrewAI's mental model is one of specialized agents collaborating on a shared task. The framework gets credentials wrong by default: every agent in the crew uses whatever sits in the process environment, which means a compromise of any agent compromises every credential the crew touches.

The right shape is one Loomal identity per agent. The researcher gets researcher-x@loomal.ai with read-only vault access; the sales agent gets sales-y@loomal.ai with the CRM write key; the support agent gets support-z@loomal.ai with the helpdesk credentials. The MCP server is configured per-agent with the matching API key.

1. Provision one identity per agent role

Create as many Loomal identities as you have agent roles. Keep them in a small config table — role name, email address, API key. In production, mint identities through the Loomal API as part of your deployment so each environment gets its own keys.

shell
# Create one identity per role and capture the API key for each
curl -X POST https://api.loomal.ai/v0/identities \
  -H "Authorization: Bearer $LOOMAL_ROOT_KEY" \
  -d '{"name": "sales-agent"}'
# repeat for researcher, support, etc.

2. Install CrewAI and the MCP adapter

crewai-tools includes an MCP adapter (MCPServerAdapter) that exposes MCP tools as CrewAI Tool objects. One adapter per identity — that's how you keep credentials from leaking across roles.

shell
pip install "crewai[tools]"

3. Wire one MCP server per agent

Each Agent constructor gets its own MCPServerAdapter, configured with that agent's specific LOOMAL_API_KEY. The model never sees the API key — it just sees the tool surface. Different agents see different credential vaults.

This is the property that makes the per-identity approach worth the setup cost: a buggy or jailbroken sales agent cannot read the support agent's vault or send mail from the support address.

crew.py
from crewai import Agent, Task, Crew
from crewai_tools import MCPServerAdapter

def loomal_tools(api_key: str):
    return MCPServerAdapter({
        "command": "npx",
        "args": ["-y", "@loomal/mcp"],
        "env": {"LOOMAL_API_KEY": api_key},
    })

researcher = Agent(
    role="Lead researcher",
    goal="Find prospects matching ICP and enrich with public data",
    backstory="Methodical, source-cites everything.",
    tools=loomal_tools(os.environ["LOOMAL_RESEARCHER_KEY"]),
)

sales = Agent(
    role="Outbound rep",
    goal="Email warm prospects and book demos",
    backstory="Concise, friendly, follows up twice.",
    tools=loomal_tools(os.environ["LOOMAL_SALES_KEY"]),
)

4. Hand off between agents via email

Because each agent has its own real email address, handoffs can be email-based. The researcher emails the sales agent at sales-y@loomal.ai with enriched leads; the sales agent picks them up from its own inbox in its next task. No shared Python objects, no message-bus glue — the inbox is the queue.

This pattern works especially well for crews that span hosts or cloud regions, because email is the most universal cross-system protocol that exists.

tasks.py
research_task = Task(
    description="Find 5 SaaS companies hiring ML engineers. Email the list to sales-y@loomal.ai with a one-line rationale per company.",
    agent=researcher,
    expected_output="Confirmation that the email was sent.",
)

sales_task = Task(
    description="Check unread mail from researcher-x@loomal.ai. For each prospect, draft a personalized outreach and send it.",
    agent=sales,
    expected_output="Number of outreach emails sent.",
)

crew = Crew(agents=[researcher, sales], tasks=[research_task, sales_task])
crew.kickoff()

5. Use vault per agent for downstream APIs

The same per-identity scoping applies to credentials. Pre-load the sales agent's vault with the CRM write key; pre-load the researcher's vault with the data-enrichment API key. Neither agent can read the other's vault even if it tries.

When a role is retired — for example, replacing the sales agent with a different model — revoke that identity. Every credential it held is invalidated; the rest of the crew is unaffected.

vault_setup.sh
# Researcher vault — read-only enrichment API key
curl -X POST https://api.loomal.ai/v0/vault \
  -H "Authorization: Bearer $LOOMAL_RESEARCHER_KEY" \
  -d '{"label": "clearbit", "value": "sk_clearbit_..."}'

# Sales vault — CRM write key (researcher cannot see this)
curl -X POST https://api.loomal.ai/v0/vault \
  -H "Authorization: Bearer $LOOMAL_SALES_KEY" \
  -d '{"label": "hubspot", "value": "pat-hubspot-..."}'

Things to watch out for

MCP processes per agent

One MCPServerAdapter per agent means one Node.js subprocess per agent. For crews with 10+ roles this adds up; consider running the MCP server as a long-lived sidecar shared across the crew with per-call API key headers (HTTP MCP transport).

Email-as-queue has latency

Email handoffs add seconds-to-minutes of latency between agents. For tightly coupled steps, use CrewAI's native context passing instead. Reserve the email pattern for handoffs that are genuinely asynchronous or span systems.

FAQ

Can two agents share one Loomal identity?

Technically yes. We don't recommend it because you lose the per-agent revocation property — the whole point of the setup. If your crew is small and you don't need that property, sharing is fine.

How do I monitor what each agent is sending?

Each identity has its own audit log accessible via the Loomal console or the audit API. Filter by identity to see exactly what one agent did, with no noise from the others.

What about the agent's delegation chain?

Each identity records the human or root agent that created it. If you mint identities at deploy time from a single root key, the chain links every agent back to the deployment principal — useful for compliance reviews.

Loomal primitives used

mail.sendmail.list_messagesmail.replyvault.getidentity.whoami

Ship it.

Free tier, no card. 30 seconds to first email.

Last updated: 2026-04-14 · See also: AutoGen, Claude Agent SDK, Claude Desktop