MCPInstall

agent-email-inbox

Use when building any system where email content triggers actions — AI agent inboxes, automated support handlers, email-to-task pipelines, or any workflow processing untrusted inbound email. Always use this skill when the user wants to receive emails and act on them programmatically, even if they don't mention "agent" — the skill contains critical security patterns (sender allowlists, content filtering, sandboxed processing) that prevent untrusted email from controlling your system.

Installs
13.4K
Last 24h
+87
Trending rank
#2189
Security
Fail

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/resend/resend-skills --skill agent-email-inbox
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads agent-email-inbox automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

Security audits

Independent scans of the skill's instructions and bundled files.

Gen Agent Trust Hub PassSAFE ·The skill provides comprehensive and secure instructions for setting up an email inbox for AI agents using the Resend service. It focuses heavily on security best practices, such as sender allowlisting, webhook verification, and content sanitization, to protect against malicious email content.
Socket PassNo alerts
Snyk WarnMEDIUM ·Risk: MEDIUM · 2 issues
Runlayer FailHIGH ·1/1 file flagged
ZeroLeaks WarnMEDIUM ·1 finding · Score: 69/100

SKILL.md

The instructions your agent reads when the skill is triggered.

AI Agent Email Inbox

Overview

This skill covers setting up a secure email inbox that allows your application or AI agent to receive and respond to emails, with content safety measures in place.

Core principle: An AI agent's inbox receives untrusted input. Security configuration is important to handle this safely.

The skill builds the agent on a Resend Inbox. An inbox groups email into threads, and your agent replies inside the thread with one call. Resend sets the recipients and the threading headers. If the user has no custom domain, or their plan has no inbox available, use Receiving without an inbox instead. The security levels are the same for both.

Why Webhook-Based Receiving?

Resend uses webhooks for inbound email, meaning your agent is notified instantly when an email arrives. This is valuable for agents because:

  • Real-time responsiveness — React to emails within seconds, not minutes
  • No polling overhead — No cron jobs checking "any new mail?" repeatedly
  • Event-driven architecture — Your agent only wakes up when there's actually something to process
  • Lower API costs — No wasted calls checking empty inboxes

Architecture

Sender → Email → Resend Inbox → inbox.email.received webhook → Your Server → AI Agent
                                                                     ↓
                                                           Security Validation
                                                                     ↓
                                                Process or Reject → Reply in the thread

SDK Version Requirements

The inbox flow needs the Node.js SDK resend >= 6.34.1, which has resend.inboxes.* and the inbox.* webhook event types. Always install the latest SDK version. If the project already has a Resend SDK installed, check the version and upgrade if needed.

The Python SDK resend >= 2.50.0 also has the inbox methods. For the other languages, call the Inboxes API over HTTP until their SDK has inbox methods, or use Receiving without an inbox.

The table below lists the minimums for the Receiving flow: webhook verification (webhooks.verify()) and email receiving (emails.receiving.get()). The resend skill lists higher minimums because it also covers newer features such as domain claims (domains.claims.*). If both skills are loaded, use the higher version.

LanguagePackageMin Version
Node.jsresend>= 6.9.2
Pythonresend>= 2.21.0
Goresend-go/v4>= 4.0.0
Rubyresend>= 1.0.0
PHPresend/resend-php>= 1.1.0
Rustresend-rs>= 0.20.0
Javaresend-java>= 4.11.0
.NETResend>= 0.2.1

Install the resend npm package: npm install resend (or the equivalent for your language). For full sending docs, install the resend skill.

Quick Start

  1. Ask the user for their email address. You need a real email address to send test emails to. Ask the user and wait for their response before proceeding.
  2. Choose your security level. Decide how to validate incoming emails before any are processed
  3. Set up the domain. Verify the user's custom domain for sending, and for receiving unless the inbox uses forwarding (see Domain Setup section)
  4. Create the inbox. Create the agent's address with resend.inboxes.create() (see Create the Inbox section)
  5. Create webhook endpoint. Handle inbox.email.received events with security built in from the start. The webhook endpoint MUST be a POST route.
  6. Set up tunneling (local dev). Use Tailscale Funnel (recommended) or ngrok. See references/webhook-setup.md
  7. Create webhook via API. Use the Resend Webhook API to register your endpoint programmatically. See references/webhook-setup.md
  8. Connect to agent. Pass validated emails to your AI agent, and reply in the thread

Before You Start: Account & API Key Setup

First Question: New or Existing Resend Account?

Ask your human:

  • New account just for the agent? → Simpler setup, full account access is fine
  • Existing account with other projects? → The agent needs a full access key, which reaches every project. Prefer a new account for the agent (see API Key Permissions)

Creating API Keys Securely

Don't paste API keys in chat! They'll be in conversation history forever.

Safer options:

  1. Environment file method: Human creates .env file directly: echo "RESEND_API_KEY=re_xxx" >> .env
  2. Password manager / secrets manager: Human stores key in 1Password, Vault, etc.
  3. If key must be shared in chat: Human should rotate the key immediately after setup

API Key Permissions

The agent's server needs a full access API key. A "Sending access" key can only reply, forward, create drafts and send drafts. Reading inbox emails or registering webhooks with it returns 401 restricted_api_key. A sending access key limited to one domain returns 403 on an inbox of another domain.

If your human has an existing Resend account with other projects, keep the risk contained:

  1. Use a dedicated account for the agent when possible, so a leaked key cannot reach other projects
  2. Keep the key on the server only. Never pass it to the AI model or put it in a prompt
  3. Rotate the key if it was ever pasted in chat or committed

Domain Setup

An inbox address lives on a custom domain the user has added to Resend. The domain must be verified for sending (DKIM and SPF). To receive email on it, either enable receiving on the domain, or create the inbox with forwarding: true.

Use a subdomain (e.g., agent.example.com) to avoid disrupting existing email services.

Option 1: Receiving on the Domain (Recommended)

The user must enable receiving in the Resend dashboard: Domains page → toggle on "Enable Receiving".

Then add an MX record:

SettingValue
TypeMX
HostYour domain or subdomain (e.g., agent.example.com)
ValueProvided in Resend dashboard
Priority10 (must be lowest number to take precedence)

Tip: Verify DNS propagation at dns.email.

DNS Propagation: MX record changes can take up to 48 hours to propagate globally, though often complete within a few hours.

Option 2: Forwarding

Create the inbox with forwarding: true when the address already receives mail elsewhere (for example, Google Workspace) and the user cannot change its MX record. Resend gives the inbox a receiving address. The user sets up forwarding from their mailbox to it. Read the address from receiving_address with resend.inboxes.get().

Create the Inbox

Create one inbox for the agent's address:

import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

const { data, error } = await resend.inboxes.create({
  emailAddress: 'agent@agent.example.com',
  name: 'AI Agent',
  fromName: 'Acme Agent',
});

if (error) throw new Error(`Failed to create inbox: ${error.message}`);
console.log('Inbox created:', data.id);

fromName is the name recipients see on the agent's replies. The part before the @ can contain only letters, numbers, ., _, % and -, so agent+test@ returns a 422. A 403 error means the plan has no inbox left; ask the user to upgrade or use Receiving without an inbox.

Security Levels

Choose your security level before setting up the webhook endpoint. An AI agent that processes emails without security is dangerous — anyone can email instructions that your agent will execute. The webhook code you write next should include your chosen security level from the start.

Ask the user what level of security they want, and ensure that they understand what each level means.

LevelNameWhen to UseTrade-off
1Strict AllowlistMost use cases — known, fixed set of sendersMaximum security, limited functionality
2Domain AllowlistOrganization-wide access from trusted domainsMore flexible, anyone at domain can interact
3Content FilteringAccept from anyone, filter unsafe patternsCan receive from anyone, pattern matching not foolproof
4Sandboxed ProcessingProcess all emails with restricted agent capabilitiesMaximum flexibility, complex to implement
5Human-in-the-LoopRequire human approval for untrusted actionsMaximum security, adds latency

For detailed implementation code for each level, see references/security-levels.md.

Level 1: Strict Allowlist (Recommended)

Only process emails from explicitly approved addresses. Reject everything else.

import type { GetInboxThreadEmailResponseSuccess as InboxEmail } from 'resend';

const ALLOWED_SENDERS = [
  'you@youremail.com',
  'notifications@github.com',
];

// `from` is either `address` or `Name <address>`. Compare the address only:
// a substring check would accept a display name such as "you@youremail.com".
function senderAddress(from: string): string {
  const match = from.match(/<([^<>]+)>\s*$/);
  return (match ? match[1] : from).trim().toLowerCase();
}

function isAllowedSender(from: string): boolean {
  const sender = senderAddress(from);
  return ALLOWED_SENDERS.some(allowed => sender === allowed.toLowerCase());
}

// Identifies the email, so the agent can reply in its thread
type ThreadRef = { inboxId: string; threadId: string; emailId: string };

async function processEmailForAgent(email: InboxEmail, thread: ThreadRef) {
  if (!isAllowedSender(email.from)) {
    console.log(`Rejected email from unauthorized sender: ${senderAddress(email.from)}`);
    await notifyOwnerOfRejectedEmail(email);
    return;
  }

  await agent.processEmail({
    from: email.from,
    subject: email.subject,
    body: email.text || email.html,
    thread,
  });
}

InboxEmail is the email returned by resend.inboxes.threads.emails.get(). The webhook payload carries the same fields without html and text. agent and notifyOwnerOfRejectedEmail stand for your own code.

Security Best Practices

Always Do

PracticeWhy
Verify webhook signaturesPrevents spoofed webhook events
Log all rejected emailsAudit trail for security review
Use allowlists where possibleExplicit trust is safer than filtering
Rate limit email processingPrevents excessive processing load
Separate trusted/untrusted handlingDifferent risk levels need different treatment

Never Do

Anti-PatternRisk
Process emails without validationAnyone can control your agent
Trust email headers for authenticationHeaders are trivially spoofed
Execute code from email contentUntrusted input should never run as code
Store email content in prompts verbatimUntrusted input mixed into prompts can alter agent behavior
Give untrusted emails full agent accessScope capabilities to the minimum needed

Webhook Endpoint

After choosing your security level and setting up your domain, create a webhook endpoint. The webhook endpoint MUST be a POST route. Resend sends all webhook events as POST requests.

Critical: Use raw body for verification. Webhook signature verification requires the raw request body.

  • Next.js App Router: Use req.text() (not req.json())
  • Express: Use express.raw({ type: 'application/json' }) on the webhook route

Next.js App Router

// app/webhook/route.ts
import { Resend } from 'resend';
import { NextRequest, NextResponse } from 'next/server';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(req: NextRequest) {
  const payload = await req.text();

  let event;
  try {
    event = resend.webhooks.verify({
      payload,
      headers: {
        id: req.headers.get('svix-id') ?? '',
        timestamp: req.headers.get('svix-timestamp') ?? '',
        signature: req.headers.get('svix-signature') ?? '',
      },
      webhookSecret: process.env.RESEND_WEBHOOK_SECRET!,
    });
  } catch {
    return new NextResponse('Invalid signature', { status: 400 });
  }

  if (event.type === 'inbox.email.received') {
    const { inbox_id, thread_id, email_id } = event.data;

    // The webhook payload has no body. Fetch the email to read it.
    const { data: email, error } = await resend.inboxes.threads.emails.get({
      inboxId: inbox_id,
      threadId: thread_id,
      emailId: email_id,
    });

    if (error) {
      // A non-2xx response makes Resend retry the webhook later
      return new NextResponse('Error', { status: 500 });
    }

    // Apply the security level chosen above
    await processEmailForAgent(email, {
      inboxId: inbox_id,
      threadId: thread_id,
      emailId: email_id,
    });
  }

  return new NextResponse('OK', { status: 200 });
}

Express

import express from 'express';
import { Resend } from 'resend';

const app = express();
const resend = new Resend(process.env.RESEND_API_KEY);

const ALLOWED_SENDERS = (process.env.ALLOWED_SENDERS || '')
  .split(',')
  .map((sender) => sender.trim().toLowerCase())
  .filter(Boolean);

const senderAddress = (from) => {
  const match = from.match(/<([^<>]+)>\s*$/);
  return (match ? match[1] : from).trim().toLowerCase();
};

const isAllowedSender = (from) => ALLOWED_SENDERS.includes(senderAddress(from));

app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  let event;
  try {
    event = resend.webhooks.verify({
      payload: req.body.toString(),
      headers: {
        id: req.headers['svix-id'],
        timestamp: req.headers['svix-timestamp'],
        signature: req.headers['svix-signature'],
      },
      webhookSecret: process.env.RESEND_WEBHOOK_SECRET,
    });
  } catch {
    res.status(400).send('Invalid signature');
    return;
  }

  if (event.type === 'inbox.email.received') {
    const { inbox_id, thread_id, email_id, email } = event.data;

    // The payload already has the sender, so reject before fetching the body
    if (!email || !isAllowedSender(email.from)) {
      console.log(`Rejected email from unauthorized sender: ${email ? senderAddress(email.from) : 'unknown'}`);
      res.status(200).send('OK'); // Return 200 even for rejected emails
      return;
    }

    const { data: fullEmail, error } = await resend.inboxes.threads.emails.get({
      inboxId: inbox_id,
      threadId: thread_id,
      emailId: email_id,
    });

    if (error) {
      res.status(500).send('Error'); // Resend retries the webhook later
      return;
    }

    await processEmailForAgent(fullEmail, { inboxId: inbox_id, threadId: thread_id, emailId: email_id });
  }

  res.status(200).send('OK');
});

app.get('/', (req, res) => res.send('Agent Email Inbox - Ready'));
app.listen(3000, () => console.log('Webhook server running on :3000'));

Resend signs inbox webhooks with the same svix-* headers as every other webhook. inbox.email.received fires for email the inbox receives. The agent's own replies fire inbox.email.sent instead, so subscribe to inbox.email.received only.

For webhook registration via API, tunneling setup, svix fallback, and retry behavior, see references/webhook-setup.md.

Replying from Your Agent

Reply inside the thread. Resend addresses the reply and sets the In-Reply-To and References headers, so the sender's mail client shows it in the same conversation:

import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

async function replyInThread(
  thread: { inboxId: string; threadId: string; emailId: string },
  body: string,
) {
  const { data, error } = await resend.inboxes.threads.emails.reply({
    inboxId: thread.inboxId,
    threadId: thread.threadId,
    emailId: thread.emailId,
    text: body,
  });

  if (error) throw new Error(`Failed to reply: ${error.message}`);
  return data.id;
}

The reply goes to the email's Reply-To addresses, or to its sender when it has none. A sender on your allowlist can set Reply-To to any address, so check email.reply_to against the allowlist too before the agent replies with anything sensitive. Leave replyAll off unless the agent should copy every recipient of the original email.

To start a new conversation, send from the inbox address with resend.emails.send(). For full sending docs, install the resend skill.

Receiving without an Inbox

Use Resend Receiving directly when the user has no custom domain, or their plan has no inbox available. The security levels above apply unchanged. What differs:

  • Address: use the auto-generated <anything>@<your-id>.resend.app address (Dashboard → Emails → Receiving → "Receiving address"), or a custom domain with receiving enabled. No inbox is created.
  • Webhook event: subscribe to email.received instead of inbox.email.received. The payload has email_id, from, to and subject, but no body.
  • Reading the email: fetch it with resend.emails.receiving.get(emailId).
  • Replying: send with resend.emails.send() and set the In-Reply-To header yourself. There are no threads.
if (event.type === 'email.received') {
  if (!isAllowedSender(event.data.from)) {
    return new NextResponse('OK', { status: 200 });
  }

  const { data: email, error } = await resend.emails.receiving.get(event.data.email_id);
  if (error) {
    return new NextResponse('Error', { status: 500 });
  }

  await agent.processEmail({ from: email.from, subject: email.subject, body: email.text || email.html });
}

The webhook verification is the same as in the inbox examples.

Environment Variables

# Required
RESEND_API_KEY=re_xxxxxxxxx
RESEND_WEBHOOK_SECRET=whsec_xxxxxxxxx

# Security Configuration
SECURITY_LEVEL=strict                    # strict | domain | filtered | sandboxed
ALLOWED_SENDERS=you@email.com,trusted@example.com
ALLOWED_DOMAINS=example.com
OWNER_EMAIL=you@email.com               # For security notifications

Common Mistakes

MistakeFix
No sender verificationAlways validate who sent the email before processing
Trusting email headersUse webhook verification, not email headers for auth
Same treatment for all emailsDifferentiate trusted vs untrusted senders
Verbose error messagesKeep error responses generic to avoid leaking internal logic
No rate limitingImplement per-sender rate limits. See references/advanced-patterns.md
Processing HTML directlyStrip HTML or use text-only to reduce complexity and risk
No logging of rejectionsLog all security events for audit
Using ephemeral tunnel URLsUse persistent URLs (Tailscale Funnel, paid ngrok) or deploy to production
Using express.json() on webhook routeUse express.raw({ type: 'application/json' }) — JSON parsing breaks signature verification
Returning non-200 for rejected emailsAlways return 200 to acknowledge receipt — otherwise Resend retries
Old Resend SDK versionresend.inboxes.* needs resend >= 6.34.1. emails.receiving.get() and webhooks.verify() also need recent versions. See SDK Version Requirements
Comparing from as a whole stringfrom can be Name <address>. Extract the address before you compare it with the allowlist
Replying to Reply-To without checking itA trusted sender can point Reply-To anywhere. Check it against the allowlist before a sensitive reply
Using a "Sending access" API keyIt can only reply, forward, create drafts and send drafts. Inbox reads and webhook setup need a full access key
Passing secret or svix-* keys to webhooks.verify()Pass webhookSecret, and headers as { id, timestamp, signature }

Testing

Use Resend's test addresses for development:

  • delivered@resend.dev — Simulates successful delivery
  • bounced@resend.dev — Simulates hard bounce

For security testing, send test emails from non-allowlisted addresses to verify rejection works correctly.

Quick verification checklist:

  1. Server is running: curl http://localhost:3000 should return a response
  2. Tunnel is working: curl https://<your-tunnel-url> should return the same response
  3. Webhook is active: Check status in Resend dashboard → Webhooks
  4. Send a test email from an allowlisted address and check server logs

Related Skills

  • For full sending, receiving and inbox docs, install the resend skill

FAQ

What does the agent-email-inbox skill do?

Use when building any system where email content triggers actions — AI agent inboxes, automated support handlers, email-to-task pipelines, or any workflow processing untrusted inbound email. Always use this skill when the user wants to receive emails and act on them programmatically, even if they don't mention "agent" — the skill contains critical security patterns (sender allowlists, content filtering, sandboxed processing) that prevent untrusted email from controlling your system.

How do I install agent-email-inbox?

Run npx skills add https://github.com/resend/resend-skills --skill agent-email-inbox in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/agent-email-inbox/ (personal) or .claude/skills/agent-email-inbox/ (project).

Which AI agents can use agent-email-inbox?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is agent-email-inbox safe to install?

Security partners have reviewed it: Gen Agent Trust Hub passed; Socket passed; Snyk flagged items to review; Runlayer flagged risks; ZeroLeaks flagged items to review. As with any skill, read the SKILL.md and bundled scripts before installing.

Who maintains agent-email-inbox?

It is published by resend in resend/resend-skills, and it is an official skill from the maker of the technology it covers. It has 13,441 recorded installs.

More from resend/resend-skills

View all →

resend

resend/resend-skills

Use when working with the Resend email API — sending transactional emails (single or batch), receiving inbound emails via webhooks, managing email templates, tracking delivery events, managing domains, contacts, broadcasts, webhooks, API keys, inboxes (threads, labels, drafts, replies), automations, events, viewing API request logs, checking account usage and quotas, or setting up the Resend SDK. Always use this skill when the user mentions Resend, even for simple tasks like "send an email with Resend" — the skill contains critical gotchas (idempotency keys, webhook verification, template variable syntax) that prevent common production issues.

OfficialBackend & APIs23.6K installs

email-best-practices

resend/resend-skills

Use when building email features, emails going to spam, high bounce rates, setting up SPF/DKIM/DMARC authentication, implementing email capture, ensuring compliance (CAN-SPAM, GDPR, CASL), handling webhooks, retry logic, making emails accessible (alt text, headings, contrast, screen readers), or deciding transactional vs marketing.

OfficialProductivity & Automation13.6K installs

resend-cli

resend/resend-skills

Operate the Resend platform from the terminal — send emails (including React Email .tsx templates via --react-email), manage domains, contacts, broadcasts, templates, webhooks, API keys, logs, automations, and events via the resend CLI. Use when the user wants to run Resend commands in the shell, scripts, or CI/CD pipelines, or send/preview React Email templates. Always load this skill before running resend commands — it contains the non-interactive flag contract and gotchas that prevent silent failures.

OfficialFrontend & Design13.4K installs

react-email

resend/resend-skills

Use when building HTML email templates with React components, adding a visual email editor to an application using the React Email visual editor, rendering emails to HTML, or sending emails with Resend. Covers welcome emails, password resets, notifications, order confirmations, newsletters, transactional emails, and the embeddable email editor component.

OfficialFrontend & Design12.7K installs

send-email

resend/resend-skills

Open the skill to read its SKILL.md instructions.

OfficialProductivity & Automation459 installs

Popular productivity & automation skills

View category →

agent-browser

vercel-labs/agent-browser

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

OfficialProductivity & Automation1.3M installs

lark-doc

open.feishu.cn

飞书云文档(Docx / Wiki)内容操作:读取、创建、编辑文档,插入或下载图片附件,以及操作思维笔记。用户提供文档 URL/token(包括 doubao.com 的 /docx/、/wiki/)时使用;按 URL 路径/token 而非域名路由;/page/ 是妙搭应用,非飞书云文档。文档内嵌资源按读取参考中的统一规则分流。独立评论操作走 lark-drive;随正文读取评论使用 docs +fetch。表格或 Base 内部数据操作不在本 skill。

lark-base

open.feishu.cn

飞书多维表格(Base)操作:建表、字段、记录、视图、统计、公式/lookup、表单、仪表盘、应用模式(BaseApp/AppMode 页面与组件)、Workspace 目录、workflow、角色权限、模板中心(多维表格模板分类/列表/搜索);遇到 Base/多维表格/bitable、BaseApp/AppMode、/base/ 或 /app/ 链接时使用。BaseApp 不走 lark-apps;文件导入/导出转 lark-drive,认证/授权转 lark-shared。

lark-drive

open.feishu.cn

飞书云空间(云盘/云存储):管理 Drive 文件和文件夹,包含上传/下载、创建文件夹、复制/移动/删除、查看元数据、查询权限设置、评论/权限/订阅、标题、版本、飞书文档密级标签(secure labels)和本地文件导入。用户需要整理云盘目录、处理云空间资源 URL/token、判断链接类型/真实 token/标题,或导入 Word/Markdown/Excel/CSV/PPTX/.base 为 docx/sheet/bitable/slides 时使用;doubao.com 云空间 URL/token 也按资源路径和 token 路由,不回退 WebFetch。不负责:文档内容编辑(走 lark-doc)、表格/Base 表内数据操作(走 lark-sheets/lark-base)、知识空间节点/成员管理(走 lark-wiki)、原生 Markdown 文件读写/patch/diff(走 lark-markdown)。

lark-shared

open.feishu.cn

Use for lark-cli setup/auth tasks: auth login/status/logout, user vs bot identity, business-domain permissions (--domain, including all/docs/drive), missing scopes, revoking authorization, or handling notice JSON.

lark-im

open.feishu.cn

飞书即时通讯:收发消息和管理群聊。发送和回复消息、搜索聊天记录、管理群聊成员、上传下载图片和文件、管理表情回复、发送应用内/短信/电话加急、发送和处理交互卡片(Interactive Card)、监听卡片按钮回调(card.action.trigger)。当用户需要发消息、查看或搜索聊天记录、下载聊天中的文件、查看群成员、搜索群、创建群聊或话题群、管理标记数据、管理 Feed 置顶(添加/移除/查询置顶会话)、管理标签数据、处理卡片回调时使用。