LOOMAL
How to

How to send email
from a Node.js AI agent.

The shortest working recipe for making a Node.js agent send email from its own DKIM-signed address. No SMTP, no OAuth.

For Node.js agents, sending email is normally either 'set up SMTP with nodemailer' or 'install the Resend/SendGrid SDK.' Both give you sending credentials without an inbox and without per-agent identity. Loomal gives you both in one HTTP call.

This recipe uses the built-in fetch (Node 18+). If you're on older Node, swap in undici or node-fetch; the shape is identical.

1. Get an API key

Sign up at console.loomal.ai, create an identity, and copy the API key (loid-...). Your agent now has a DKIM-signed address it can send from.

.env
LOOMAL_API_KEY=loid-your-api-key

2. Send with fetch

POST to /v0/messages/send. The body is a JSON object with to (array), subject (string), and text (string). Response includes messageId and threadId — save the threadId if you plan to correlate replies later.

send.ts
const API = "https://api.loomal.ai/v0";

async function send(to: string, subject: string, text: string) {
  const res = await fetch(`${API}/messages/send`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.LOOMAL_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ to: [to], subject, text }),
  });
  if (!res.ok) throw new Error(`Loomal ${res.status}: ${await res.text()}`);
  return res.json() as Promise<{ messageId: string; threadId: string }>;
}

await send("alice@example.com", "Hello", "From a Node.js agent.");

3. Wrap as a tool for the Vercel AI SDK

If your agent uses the AI SDK's tool-calling loop, define the tool with zod and hand it to streamText. The model decides when to call it.

tool.ts
import { tool, streamText } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";

const sendEmail = tool({
  description: "Send an email from the agent's own address.",
  parameters: z.object({
    to: z.string().email(),
    subject: z.string(),
    text: z.string(),
  }),
  execute: async ({ to, subject, text }) => send(to, subject, text),
});

const result = await streamText({
  model: openai("gpt-4o-mini"),
  tools: { sendEmail },
  maxSteps: 4,
  prompt: "Email alice@example.com thanking her for today's demo.",
});

4. Or use the MCP server

For a shorter path, register Loomal as an MCP server. The AI SDK, LangChain, Mastra, and Claude Agent SDK all support this; the agent gets mail.send, mail.reply, and the rest without any tool wrapper code. See the Vercel AI SDK guide for the full setup.

mcp-setup.ts
import { experimental_createMCPClient } from "ai";
import { Experimental_StdioMCPTransport } from "ai/mcp-stdio";

const client = await experimental_createMCPClient({
  transport: new Experimental_StdioMCPTransport({
    command: "npx",
    args: ["-y", "@loomal/mcp"],
    env: { LOOMAL_API_KEY: process.env.LOOMAL_API_KEY! },
  }),
});
const tools = await client.tools();

FAQ

Does this work in edge runtimes (Vercel Edge, Cloudflare Workers)?

The REST approach does — fetch is available. The MCP stdio transport is not, since edge runtimes can't spawn subprocesses. Use the HTTP MCP transport or just call REST directly from edge.

Can I send HTML instead of text?

Yes — add an html field to the body alongside text. Most email clients prefer the HTML version but fall back to text when it's missing.

How do I send to multiple recipients?

The to field is an array. You can also include cc and bcc arrays. Each message is delivered once per recipient; Loomal handles the envelope addressing.

Give your agent its own identity.

Free tier, 30-second setup.

Last updated: 2026-04-15