Skill: vber/skill-alimail (version 0.1.2)

--- name: alimail-manager description: 提供阿里邮箱API调用能力，支持用户信息查询、邮件详情获取、邮件搜索；当用户需要查询企业邮箱用户信息、查看特定邮件内容、搜索符合条件的邮件时使用 required_env: - ALMAIL_APP_ID - ALMAIL_SECRET auth: type: oauth2_client_credentials dependency: system: - npm install alimail-node-sdk --- # 阿里邮箱管理 ## 任务目标 - 本 Skill 用于：管理阿里邮箱用户和邮件数据 - 能力包含：用户信息查询、邮件详情获取、邮件列表搜索、分页查询 - 触发条件：用户需要查询企业邮箱用户、查看邮件内容、搜索邮件列表 ## 前置准备 - 依赖说明：需要安装阿里邮箱SDK ```bash npm install alimail-node-sdk ``` - 认证方式：OAuth2 `client_credentials` - 必填环境变量： - `ALMAIL_APP_ID`：阿里邮箱应用 ID - `ALMAIL_SECRET`：阿里邮箱应用 Secret ## 操作步骤 ### 标准流程 1. **执行具体操作** - 获取用户信息：调用 `scripts/get_user.js` - 获取邮件详情：调用 `scripts/get_message.js` - 搜索邮件：调用 `scripts/search_messages.js` 2. **处理结果** - 解析返回的JSON数据 - 根据业务需求提取关键信息 - 提供清晰的总结和建议 ### 可选分支 - 当 **需要获取扩展字段**：在参数中指定 `select` 字段 - 当 **需要分页查询**：使用 `search_messages.js` 的 cursor 机制 - 当 **遇到API限流**：SDK会自动处理重试，建议适当降低请求频率 ## 资源索引 - API参考： - [references/alimail-api.md](references/alimail-api.md) (何时读取：需要了解API参数、字段定义、KQL查询语法) ## 注意事项 - 邮件搜索支持KQL查询语法，详见参考文档 - 使用时必须配置 `ALMAIL_APP_ID` 和 `ALMAIL_SECRET` ## 使用示例 ### 示例1：获取用户信息 ```bash node scripts/get_user.js --email "[REDACTED_SECRET]" --select "phone,managerInfo" ``` ### 示例2：获取邮件详情 ```bash node scripts/get_message.js --email "[REDACTED_SECRET]" --message-id "AAMkAGI2T..." --select "body,toRecipients" ``` ### 示例3：搜索邮件 ```bash node scripts/search_messages.js --email "[REDACTED_SECRET]" --query 'fromEmail="[REDACTED_SECRET]"' --size 20 ```

path: README.md
content: # 阿里邮箱管理技能 (skill-alimail)

提供阿里邮箱 API 调用能力，支持用户信息查询、邮件详情获取、邮件搜索。

## 🛠️ 前置准备

1. **环境变量**
   使用前需配置阿里邮箱的环境变量：
   - `ALMAIL_APP_ID`：阿里邮箱应用 ID
   - `ALMAIL_SECRET`：阿里邮箱应用 Secret

2. **认证方式**
   当前使用 OAuth2 `client_credentials` 流程，由 `alimail-node-sdk` 在请求时处理令牌申请。

3. **安装依赖**
   ```bash
   npm install alimail-node-sdk
   ```
## ✨ 主要功能

- **用户信息查询** (`scripts/get_user.js`)：获取邮箱用户的详细资料（支持选择扩展字段）
- **邮件详情获取** (`scripts/get_message.js`)：通过 `message-id` 查看特定邮件的具体内容
- **邮件搜索** (`scripts/search_messages.js`)：支持 KQL 查询语法、分页，快速筛选邮件

## 🚀 快速上手

### 1. 获取用户信息
```bash
node scripts/get_user.js --email "[REDACTED_SECRET]" --select "phone,managerInfo"
```

### 2. 查看邮件详情
```bash
node scripts/get_message.js --email "[REDACTED_SECRET]" --message-id "MESSAGE_ID" --select "body,toRecipients"
```

### 3. 搜索邮件
```bash
node scripts/search_messages.js --email "[REDACTED_SECRET]" --query 'fromEmail="[REDACTED_SECRET]"' --size 20
```

---
💡 **更多文档**：
- API 参数及 KQL 查询语法详见：[references/alimail-api.md](references/alimail-api.md)


path: references/alimail-api.md
content: # 阿里邮箱API参考文档

## 目录
- [API概述](#api概述)
- [用户信息查询](#用户信息查询)
- [邮件详情获取](#邮件详情获取)
- [邮件搜索](#邮件搜索)
- [KQL查询语法](#kql查询语法)
- [常见字段说明](#常见字段说明)

## API概述

阿里邮箱开放API基于OAuth2认证，使用client_credentials模式获取access_token。

### 认证方式
- 授权模式：OAuth2 client_credentials
- 请求头：`Authorization: Bearer {access_token}`
- 限流：单域总流量不超过40次/秒

### 基础URL
```
https://alimail-cn.aliyuncs.com
```

### 错误处理
SDK会自动处理以下情况：
- 401未授权：自动刷新token后重试
- 429限流：指数退避重试
- 5xx服务器错误：自动重试

## 用户信息查询

### 接口
```
GET /v2/users/{id | email}
```

### 权限要求
- User.Read.All
- User.ReadWrite.All

### 参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| identifier | string | 是 | 用户ID或邮箱地址 |
| select | string或string[] | 否 | 要返回的可选字段 |

### 常用$select字段
- `phone` - 电话号码
- `managerInfo` - 经理信息
- `homeLocation` - 位置信息
- `departmentPath` - 部门路径
- `lastLoginTime` - 最后登录时间
- `customFields` - 自定义字段

### 返回字段
```json
{
  "id": "用户ID",
  "email": "邮箱地址",
  "name": "姓名",
  "phone": "电话",
  "department": "部门",
  "jobTitle": "职位"
}
```

## 邮件详情获取

### 接口
```
GET /v2/users/{email}/messages/{id}
```

### 权限要求
- Mail.Read.All
- Mail.ReadWrite.All

### 参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| email | string | 是 | 用户邮箱地址 |
| messageId | string | 是 | 邮件唯一标识 |
| select | string或string[] | 否 | 要返回的字段 |
| unwrapMessage | boolean | 否 | 是否仅返回message字段，默认true |

### 常用$select字段
- `internetMessageId` - 互联网消息ID
- `body` - 邮件正文
- `toRecipients` - 收件人列表
- `ccRecipients` - 抄送人列表
- `bccRecipients` - 密送人列表
- `sender` - 发件人
- `replyTo` - 回复地址
- `receivedDateTime` - 接收时间
- `lastModifiedDateTime` - 最后修改时间
- `tags` - 标签
- `subject` - 主题

### 返回字段
```json
{
  "id": "邮件ID",
  "internetMessageId": "互联网消息ID",
  "subject": "邮件主题",
  "body": {
    "contentType": "HTML",
    "content": "邮件正文内容"
  },
  "sender": {
    "emailAddress": {
      "name": "发件人姓名",
      "address": "发件人邮箱"
    }
  },
  "toRecipients": [
    {
      "emailAddress": {
        "name": "收件人姓名",
        "address": "收件人邮箱"
      }
    }
  ],
  "receivedDateTime": "2025-01-01T00:00:00Z"
}
```

## 邮件搜索

### 接口
```
POST /v2/users/{email}/messages/query
```

### 权限要求
- Mail.Read.All
- Mail.ReadWrite.All

### 参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| email | string | 是 | 用户邮箱地址 |
| query | string | 是 | KQL查询语句 |
| cursor | string | 是 | 分页游标，首次传空字符串 |
| size | number | 是 | 每页数量，取值1-100 |
| select | string或string[] | 否 | 要返回的字段 |

### 返回字段
```json
{
  "messages": [...],
  "nextCursor": "下一页游标"
}
```

### 分页查询
1. 第一次请求：cursor传空字符串 `""`
2. 后续请求：使用返回的 `nextCursor` 作为新的 cursor
3. 当 `nextCursor` 为空时，表示没有更多数据

## KQL查询语法

### 基本语法
KQL (Keyword Query Language) 用于构造复杂的查询条件。

### 常用操作符
- `=` 等于
- `>` 大于
- `<` 小于
- `>=` 大于等于
- `<=` 小于等于
- `AND` 逻辑与
- `OR` 逻辑或
- `NOT` 逻辑非

### 常用查询字段

#### 邮件相关
- `fromEmail` - 发件人邮箱
- `toRecipients` - 收件人
- `subject` - 邮件主题
- `receivedDateTime` - 接收时间
- `isRead` - 是否已读

#### 示例查询

**查询来自特定发件人的邮件**
```
fromEmail="[REDACTED_SECRET]"
```

**查询特定时间之后的邮件**
```
date>2025-01-01T00:00:00Z
```

**查询特定主题的邮件**
```
subject="项目周报"
```

**组合查询（时间+发件人）**
```
date>2025-01-01T00:00:00Z AND fromEmail="[REDACTED_SECRET]"
```

**排除已删除文件夹**
```
date>2025-01-01T00:00:00Z AND (NOT folderId:3)
```

**查询包含多个条件的邮件**
```
fromEmail="[REDACTED_SECRET]" OR fromEmail="[REDACTED_SECRET]"
```

**使用引号处理特殊字符**
```
subject="项目: Q1报告"
```

## 常见字段说明

### 用户字段
| 字段 | 类型 | 说明 |
|------|------|------|
| id | string | 用户唯一ID |
| email | string | 邮箱地址 |
| name | string | 姓名 |
| phone | string | 电话号码 |
| department | string | 部门名称 |
| jobTitle | string | 职位 |
| managerInfo | object | 经理信息 |
| homeLocation | object | 位置信息 |

### 邮件字段
| 字段 | 类型 | 说明 |
|------|------|------|
| id | string | 邮件唯一ID |
| internetMessageId | string | 互联网消息ID |
| subject | string | 邮件主题 |
| body | object | 邮件正文 |
| sender | object | 发件人信息 |
| toRecipients | array | 收件人列表 |
| ccRecipients | array | 抄送人列表 |
| bccRecipients | array | 密送人列表 |
| replyTo | array | 回复地址 |
| receivedDateTime | string | 接收时间（ISO8601格式） |
| lastModifiedDateTime | string | 最后修改时间（ISO8601格式） |
| tags | array | 标签列表 |
| isReadReceiptRequested | boolean | 是否要求已读回执 |

## 注意事项

1. **限流处理**：API限流为40次/秒，超出会返回429状态码，SDK会自动重试
2. **分页查询**：使用cursor机制，每次最多返回100条邮件
3. **字段选择**：使用`$select`参数可以减少返回数据量，提高性能
4. **时间格式**：所有时间字段使用ISO8601格式，例如 `2025-01-01T00:00:00Z`
5. **查询语法**：KQL查询语句需要使用引号包裹字符串值
6. **权限要求**：不同的API需要不同的权限，确保应用已正确配置


path: scripts/create_client.js
content: #!/usr/bin/env node

const { AliMailClient } = require('alimail-node-sdk');
const fs = require('fs');
const path = require('path');

/**
 * 创建阿里邮箱客户端
 * 
 * 授权方式: OAuth2 client_credentials（由 SDK 内部处理令牌申请）
 * 凭证环境变量: ALMAIL_APP_ID, ALMAIL_SECRET
 */
function createClient() {
    // 1. 获取凭证
    const appId = process.env.ALMAIL_APP_ID;
    const appSecret = process.env.ALMAIL_SECRET;

    if (!appId || !appSecret) {
        throw new Error('缺少阿里邮箱凭证配置，请检查环境变量 ALMAIL_APP_ID 和 ALMAIL_SECRET');
    }

    // 2. 创建客户端
    const client = new AliMailClient({
        appId,
        appSecret,
        baseUrl: 'https://alimail-cn.aliyuncs.com',
        timeoutMs: 30000,
        maxRetries: 3,
    });

    return client;
}

module.exports = { createClient };

// 如果直接运行此脚本，输出客户端信息
if (require.main === module) {
    try {
        const client = createClient();
        console.log('阿里邮箱客户端创建成功');
    } catch (error) {
        console.error('创建客户端失败:', error.message);
        process.exit(1);
    }
}


path: scripts/get_message.js
content: #!/usr/bin/env node

const { createClient } = require('./create_client');

/**
 * 获取邮件详情
 * 
 * 参数：
 * --email: 用户邮箱地址（必填）
 * --message-id: 邮件唯一标识（必填）
 * --select: 要返回的字段，逗号分隔（可选）
 * --unwrap: 是否仅返回message字段（默认true，设为false返回完整响应）
 * 
 * 示例：
 * node scripts/get_message.js --email "[REDACTED_SECRET]" --message-id "AAMkAGI2T..."
 * node scripts/get_message.js --email "[REDACTED_SECRET]" --message-id "AAMkAGI2T..." --select "body,toRecipients,sender"
 */
async function main() {
    const args = process.argv.slice(2);
    const params = {};

    // 解析命令行参数
    for (let i = 0; i < args.length; i++) {
        if (args[i] === '--email' && args[i + 1]) {
            params.email = args[i + 1];
            i++;
        } else if (args[i] === '--message-id' && args[i + 1]) {
            params.messageId = args[i + 1];
            i++;
        } else if (args[i] === '--select' && args[i + 1]) {
            params.select = args[i + 1].split(',').map(s => s.trim());
            i++;
        } else if (args[i] === '--unwrap' && args[i + 1]) {
            params.unwrapMessage = args[i + 1].toLowerCase() === 'true';
            i++;
        }
    }

    // 验证必填参数
    if (!params.email) {
        console.error('错误：缺少必填参数 --email');
        console.error('用法：node scripts/get_message.js --email <邮箱地址> --message-id <邮件ID> [--select <字段列表>] [--unwrap <true|false>]');
        process.exit(1);
    }

    if (!params.messageId) {
        console.error('错误：缺少必填参数 --message-id');
        console.error('用法：node scripts/get_message.js --email <邮箱地址> --message-id <邮件ID> [--select <字段列表>] [--unwrap <true|false>]');
        process.exit(1);
    }

    try {
        // 创建客户端
        const client = createClient();

        // 构造选项
        const options = {};
        if (params.select && params.select.length > 0) {
            options.select = params.select;
        }
        if (params.unwrapMessage !== undefined) {
            options.unwrapMessage = params.unwrapMessage;
        } else {
            options.unwrapMessage = true; // 默认值
        }

        // 获取邮件详情
        console.log(`正在获取邮件详情: ${params.messageId}`);
        const message = await client.getMessage(params.email, params.messageId, options);

        // 输出结果
        console.log('\n=== 邮件详情 ===');
        console.log(JSON.stringify(message, null, 2));

    } catch (error) {
        console.error('获取邮件详情失败:');
        
        if (error.name === 'AliMailSdkError') {
            console.error(`  错误信息: ${error.message}`);
            console.error(`  HTTP状态码: ${error.status}`);
            console.error(`  错误代码: ${error.code}`);
            console.error(`  请求ID: ${error.requestId}`);
            console.error(`  请求URL: ${error.url}`);
            if (error.details) {
                console.error(`  详细信息: ${JSON.stringify(error.details)}`);
            }
        } else {
            console.error(`  ${error.message}`);
        }
        
        process.exit(1);
    }
}

main();


path: scripts/get_user.js
content: #!/usr/bin/env node

const { createClient } = require('./create_client');

/**
 * 获取用户信息
 * 
 * 参数：
 * --email: 用户邮箱地址（必填）
 * --select: 要返回的可选字段，逗号分隔（可选）
 * 
 * 示例：
 * node scripts/get_user.js --email "[REDACTED_SECRET]"
 * node scripts/get_user.js --email "[REDACTED_SECRET]" --select "phone,managerInfo,customFields"
 */
async function main() {
    const args = process.argv.slice(2);
    const params = {};

    // 解析命令行参数
    for (let i = 0; i < args.length; i++) {
        if (args[i] === '--email' && args[i + 1]) {
            params.email = args[i + 1];
            i++;
        } else if (args[i] === '--select' && args[i + 1]) {
            params.select = args[i + 1].split(',').map(s => s.trim());
            i++;
        }
    }

    // 验证必填参数
    if (!params.email) {
        console.error('错误：缺少必填参数 --email');
        console.error('用法：node scripts/get_user.js --email <邮箱地址> [--select <字段列表>]');
        process.exit(1);
    }

    try {
        // 创建客户端
        const client = createClient();

        // 构造选项
        const options = {};
        if (params.select && params.select.length > 0) {
            options.select = params.select;
        }

        // 获取用户信息
        console.log(`正在获取用户信息: ${params.email}`);
        const user = await client.getUser(params.email, options);

        // 输出结果
        console.log('\n=== 用户信息 ===');
        console.log(JSON.stringify(user, null, 2));

    } catch (error) {
        console.error('获取用户信息失败:');
        
        if (error.name === 'AliMailSdkError') {
            console.error(`  错误信息: ${error.message}`);
            console.error(`  HTTP状态码: ${error.status}`);
            console.error(`  错误代码: ${error.code}`);
            console.error(`  请求ID: ${error.requestId}`);
            console.error(`  请求URL: ${error.url}`);
            if (error.details) {
                console.error(`  详细信息: ${JSON.stringify(error.details)}`);
            }
        } else {
            console.error(`  ${error.message}`);
        }
        
        process.exit(1);
    }
}

main();


path: scripts/search_messages.js
content: #!/usr/bin/env node

const { createClient } = require('./create_client');

/**
 * 搜索邮件
 * 
 * 参数：
 * --email: 用户邮箱地址（必填）
 * --query: KQL查询语句（必填）
 * --cursor: 分页游标，首次传空字符串（可选，默认空字符串）
 * --size: 每页数量，取值1-100（可选，默认20）
 * --select: 要返回的字段，逗号分隔（可选）
 * 
 * 示例：
 * node scripts/search_messages.js --email "[REDACTED_SECRET]" --query 'fromEmail="[REDACTED_SECRET]"'
 * node scripts/search_messages.js --email "[REDACTED_SECRET]" --query 'date>2025-01-01' --size 50
 */
async function main() {
    const args = process.argv.slice(2);
    const params = {};

    // 解析命令行参数
    for (let i = 0; i < args.length; i++) {
        if (args[i] === '--email' && args[i + 1]) {
            params.email = args[i + 1];
            i++;
        } else if (args[i] === '--query' && args[i + 1]) {
            params.query = args[i + 1];
            i++;
        } else if (args[i] === '--cursor' && args[i + 1]) {
            params.cursor = args[i + 1];
            i++;
        } else if (args[i] === '--size' && args[i + 1]) {
            params.size = parseInt(args[i + 1], 10);
            i++;
        } else if (args[i] === '--select' && args[i + 1]) {
            params.select = args[i + 1].split(',').map(s => s.trim());
            i++;
        }
    }

    // 验证必填参数
    if (!params.email) {
        console.error('错误：缺少必填参数 --email');
        console.error('用法：node scripts/search_messages.js --email <邮箱地址> --query <KQL查询语句> [--cursor <游标>] [--size <数量>] [--select <字段列表>]');
        process.exit(1);
    }

    if (!params.query) {
        console.error('错误：缺少必填参数 --query');
        console.error('用法：node scripts/search_messages.js --email <邮箱地址> --query <KQL查询语句> [--cursor <游标>] [--size <数量>] [--select <字段列表>]');
        process.exit(1);
    }

    // 设置默认值
    if (!params.cursor) {
        params.cursor = '';
    }
    if (!params.size) {
        params.size = 20;
    }
    if (params.size < 1 || params.size > 100) {
        console.error('错误：size参数必须在1-100之间');
        process.exit(1);
    }

    try {
        // 创建客户端
        const client = createClient();

        // 构造选项
        const options = {
            query: params.query,
            cursor: params.cursor,
            size: params.size,
        };
        if (params.select && params.select.length > 0) {
            options.select = params.select;
        }

        // 搜索邮件
        console.log(`正在搜索邮件: ${params.query}`);
        console.log(`查询参数: size=${params.size}, cursor="${params.cursor}"`);
        const result = await client.searchMessages(params.email, options);

        // 输出结果
        console.log('\n=== 搜索结果 ===');
        console.log(`找到邮件数量: ${result.messages.length}`);
        console.log(`下一页游标: ${result.nextCursor}`);
        
        if (result.messages.length > 0) {
            console.log('\n邮件列表:');
            result.messages.forEach((msg, index) => {
                console.log(`\n[${index + 1}] 邮件ID: ${msg.id}`);
                console.log(`    主题: ${msg.subject || '(无主题)'}`);
                console.log(`    发件人: ${msg.sender?.emailAddress?.name || msg.sender?.emailAddress?.address || '未知'}`);
                console.log(`    接收时间: ${msg.receivedDateTime || '未知'}`);
                if (msg.internetMessageId) {
                    console.log(`    互联网消息ID: ${msg.internetMessageId}`);
                }
            });
        }

        console.log('\n=== 完整数据 ===');
        console.log(JSON.stringify(result, null, 2));

    } catch (error) {
        console.error('搜索邮件失败:');
        
        if (error.name === 'AliMailSdkError') {
            console.error(`  错误信息: ${error.message}`);
            console.error(`  HTTP状态码: ${error.status}`);
            console.error(`  错误代码: ${error.code}`);
            console.error(`  请求ID: ${error.requestId}`);
            console.error(`  请求URL: ${error.url}`);
            if (error.details) {
                console.error(`  详细信息: ${JSON.stringify(error.details)}`);
            }
        } else {
            console.error(`  ${error.message}`);
        }
        
        process.exit(1);
    }
}

main();


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)