Skip to content
Writing
NewTutorialAI agentsLangChainCrewAI

How to give an AI agent email access safely

Step-by-step tutorial on minting a scoped agent key, setting up domain allowlists, and integrating email tools into LangChain, CrewAI, and TypeScript loops safely.

Tayyab MughalFounder & AI Chief3 min read

The master key anti-pattern

The most common security mistake in AI agent development is pasting a master production API key into an agent’s environment variables. If the agent gets stuck in a loop, it drains your quota; if it encounters a prompt injection in a customer ticket, an attacker can command it to email anyone from your brand.

To give an agent email access safely, you must enforce the principle of least privilege at the API gateway.

Step 1: Mint a scoped agent key with an allowlist

Create a dedicated API key constrained strictly to sending, with an allowlist limited to internal test recipients or your corporate domain:

BASH
# Mint an agent key via the SadaSend CLI or dashboard
sadasend keys create \
  --name "customer-triage-agent" \
  --scopes "send,read" \
  --allowlist "@yourcompany.com" \
  --rate-limit 30

Step 2: Connecting to LangChain (Python)

Here is how to create a custom LangChain tool using the SadaSend SDK with built-in error handling for allowlist violations:

PYTHON
from langchain.tools import tool
import requests
import os

@tool
def send_agent_email(to_email: str, subject: str, body: str) -> str:
    """Send an email to a customer or internal stakeholder safely."""
    response = requests.post(
        "https://api.sadasend.com/v1/emails",
        headers={"Authorization": f"Bearer {os.environ['SADASEND_AGENT_KEY']}"},
        json={
            "from": "triage-bot@yourdomain.com",
            "to": to_email,
            "subject": subject,
            "text": body,
        }
    )
    if response.status_code == 200:
        return f"Email sent successfully. ID: {response.json()['id']}"
    elif response.status_code == 403:
        return f"Guardrail refused send: {response.json()['message']}"
    else:
        return f"Error sending email: {response.text}"

Step 3: connecting to CrewAI or TypeScript agent loops

In TypeScript agent architectures, initialize the SadaSend client with your scoped key:

TYPESCRIPT
import { SadaSend } from 'sadasend';

const sadasend = new SadaSend({ apiKey: process.env.SADASEND_AGENT_KEY });

async function executeAgentOutbound(recipient: string, subject: string, markdown: string) {
  try {
    const { id } = await sadasend.emails.send({
      from: 'triage@yourdomain.com',
      to: recipient,
      subject: subject,
      markdown: markdown,
    });
    console.log(`Dispatched message ${id}`);
  } catch (err: any) {
    if (err.code === 'refused_recipient_outside_allowlist') {
      console.warn('Agent tried to email outside allowed domain:', recipient);
    }
  }
}

Step 4: Dry-run verification before production launch

Set your agent key to dry-run mode in your staging environment. The API will validate DNS, DKIM alignment, and allowlists, but drop the message before it hits external mail servers — giving you full confidence in CI/CD.

Early Access

Building AI agents that send email?

Join the SadaSend early access waitlist to get scoped API keys, recipient allowlists, and Model Context Protocol (MCP) servers upon launch.

Use Case:
One email when it opens
Social Hashtags & Share
#EmailAPI#DeveloperTools#Tutorial#AIAgents#AIEngineering#LangChain
Tayyab MughalFounder & AI Chief

Building SadaSend — transactional email with an MCP server that has a ceiling. Writes about deliverability, email infrastructure, and what happens when you hand an autonomous agent a sending credential.