OpenClaw extension

Operations

Drop a single TypeScript file into ~/.openclaw/extensions/ to give every OpenClaw agent native myagentmail tools.

OpenClaw loads any .ts file in ~/.openclaw/extensions/ as a tool extension at startup. Below is the full extension that registers four core tools — copy it to ~/.openclaw/extensions/myagentmail.ts and set MYAGENTMAIL_KEY in the OpenClaw env.

// ~/.openclaw/extensions/myagentmail.ts
//
// Native myagentmail tools for OpenClaw agents.
// Set MYAGENTMAIL_KEY in the OpenClaw process env.

import type { ExtensionApi } from "openclaw/extensions";

const API = "https://myagentmail.com/v1";

function key(): string {
  const k = process.env.MYAGENTMAIL_KEY || "";
  if (!k) throw new Error("MYAGENTMAIL_KEY env var is not set");
  return k;
}

async function mam(method: string, path: string, body?: unknown) {
  const r = await fetch(`${API}${path}`, {
    method,
    headers: { "X-API-Key": key(), "Content-Type": "application/json" },
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!r.ok) throw new Error(`mam ${method} ${path} → ${r.status}: ${await r.text()}`);
  return r.json();
}

export function register(api: ExtensionApi) {
  api.registerTool({
    name: "MAM_SEND_EMAIL",
    description: "Send an email from a myagentmail inbox. Set verified=true after MX-checking the recipient.",
    parameters: {
      type: "object",
      required: ["inboxId", "to", "subject"],
      properties: {
        inboxId:   { type: "string" },
        to:        { type: "string", description: "Recipient email or array of emails." },
        subject:   { type: "string" },
        plainBody: { type: "string" },
        htmlBody:  { type: "string" },
        verified:  { type: "boolean", default: true },
      },
    },
    async execute(_id, params: any) {
      const body = { ...params };
      delete body.inboxId;
      const result = await mam("POST", `/inboxes/${params.inboxId}/send`, body);
      return { content: [{ type: "text", text: JSON.stringify(result) }] };
    },
  });

  api.registerTool({
    name: "MAM_LIST_INBOX",
    description: "List inbound messages in a myagentmail inbox.",
    parameters: {
      type: "object",
      required: ["inboxId"],
      properties: {
        inboxId: { type: "string" },
        limit:   { type: "number", default: 20 },
      },
    },
    async execute(_id, params: any) {
      const result = await mam(
        "GET",
        `/inboxes/${params.inboxId}/messages?direction=inbound&limit=${params.limit ?? 20}`
      );
      return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
    },
  });

  api.registerTool({
    name: "MAM_REPLY",
    description: "Reply to a myagentmail message in-thread.",
    parameters: {
      type: "object",
      required: ["inboxId", "messageId", "plainBody"],
      properties: {
        inboxId:   { type: "string" },
        messageId: { type: "string" },
        plainBody: { type: "string" },
      },
    },
    async execute(_id, params: any) {
      const result = await mam(
        "POST",
        `/inboxes/${params.inboxId}/reply/${params.messageId}`,
        { plainBody: params.plainBody }
      );
      return { content: [{ type: "text", text: JSON.stringify(result) }] };
    },
  });

  api.registerTool({
    name: "MAM_CREATE_INBOX",
    description: "Provision a new myagentmail inbox.",
    parameters: {
      type: "object",
      properties: {
        username:    { type: "string" },
        displayName: { type: "string" },
      },
    },
    async execute(_id, params: any) {
      const result = await mam("POST", "/inboxes", params);
      return { content: [{ type: "text", text: JSON.stringify(result) }] };
    },
  });
}

Restart OpenClaw and the four MAM_* tools become available to every agent. Extend the file with whatever endpoints your agents need — the pattern repeats for every route in the API reference.