@dyanet/imap

中文文档
0.6.1发布于 2026/09/27MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 2725

一个现代零依赖性 TypeScript IMAP 客户端库 - 为 Imp- simp 和 Imp 套件所倒置

中文使用文档
文档目录28 节
  1. 背景情况
  2. 特征
  3. 安装
  4. 快速启动
  5. 建筑
  6. 图层责任
  7. API 参考
  8. 图像快捷
  9. 配置
  10. OAuth2 认证 (Gmail, Microsoft 365)
  11. 搜索标准
  12. 获取选项
  13. 页眉解析
  14. 标准旗帜
  15. 扩展能力
  16. IDLE (RFC 2177) (法语)
  17. 联系(RFC 7162)
  18. QRESYNC (RFC 7162) (中文(简体) )
  19. 能力检测
  20. 处理错误
  21. A. 从简单移民
  22. 试试看自己的邮箱
  23. 1. 实例应用软件——这是我们用它来测试的
  24. 2. 直接针对Gmail或Outlook的图书馆
  25. 3. 不需要邮箱
  26. 类型脚本支持
  27. 所需资源
  28. 许可证

@ dianet/ 地图

CI Coverage npm version npm downloads GitHub Packages License: MIT

一个现代的零依赖性 TypeScript IMAP 客户端库,可以恢复已中止的功能 简单 软件包.

背景情况

这个图书馆是作为两个流行但现在已经过时的IMAP图书馆的现代取而代之:

  • 简单 - 一个流行的包装 imap 用于简化 IMAP 操作的软件包。 最近一次更新于2020年,现已贬值.
  • 图像 - IMAP客户端 imap-simple 取决于。 2019年最后一次更新,不再维持.

这两个图书馆都了解安全漏洞,与现代Node.js版本不相容. @dyanet/imap 以兼容的API提供新的零依赖性执行,使移徙变得直截了当.

特征

  • 无依赖: 只使用已内置模块(net, (中文(简体) ), tls, (中文(简体) ), crypto, (中文(简体) ), events(中文(简体) )
  • 类型脚本第一: 在 TypeScript 中以严格模式写入, 包含完整类型定义
  • 简单兼容: 方便迁移的倒置替换 API
  • 承诺: 用于所有操作的现代合成/等待 API
  • OAuth2 辅助: Gmail 和 Microsoft 365 的 XOOITH2 认证
  • IMAP 扩展:IDLE,CONDSTORE,QRESYNC支持实时更新并高效同步
  • 小脚印: 50KB 下的目标捆绑大小

安装

npm install @dyanet/imap

快速启动

import { ImapClient } from '@dyanet/imap';

const client = await ImapClient.connect({
  imap: {
    host: 'imap.example.com',
    port: 993,
    user: '[email protected]',
    password: 'password',
    tls: true
  }
});

// Open INBOX
const mailbox = await client.openBox('INBOX');
console.log(`Total messages: ${mailbox.messages.total}`);

// Search for unread messages
const messages = await client.search(['UNSEEN'], { bodies: ['HEADER'] });

// Process messages
for (const msg of messages) {
  console.log(`UID: ${msg.uid}, Flags: ${msg.attributes.flags}`);
}

// Close connection
await client.end();

建筑

图书馆采用分层结构,将关注事项分开,并实现可测试性:

┌─────────────────────────────────────────────────────────────┐
│                    ImapClient (Public API)                  │
│  connect() | openBox() | search() | fetch() | move() | end()│
├─────────────────────────────────────────────────────────────┤
│                    Command Layer                            │
│  CommandBuilder | ResponseParser | MimeParser               │
├─────────────────────────────────────────────────────────────┤
│                    Protocol Layer                           │
│  ImapProtocol | TagGenerator | LiteralHandler               │
├─────────────────────────────────────────────────────────────┤
│                    Transport Layer                          │
│  ImapConnection | TLS/TCP Socket Management                 │
└─────────────────────────────────────────────────────────────┘

图层责任

  • 运输层: 使用节点管理原始 TCP/ TLS 套接字连接 net 财务报告和审定财务报表 tls 模块
  • 协议层: 执行IMAP协议解析,包括有标记/未标记的回复和文字
  • 命令层: 构建 IMAP 命令并解析命令特定响应
  • 公共 API: 显示用户界面 ImapClient 基于承诺方法的类

API 参考

图像快捷

IMAP业务的主要客户类.

静态方法

ImapClient.connect(config: ImapConfig): Promise<ImapClient>

创建新客户端并连接到服务器.

const client = await ImapClient.connect({
  imap: {
    host: 'imap.example.com',
    port: 993,
    user: '[email protected]',
    password: 'password',
    tls: true,
    tlsOptions: { rejectUnauthorized: true }
  }
});

实例方法

end(): Promise<void>

通过发送LOGOUT命令来优雅地关闭连接 .

await client.end();
getBoxes(): Promise<MailboxTree>

列出服务器上的所有邮箱.

const boxes = await client.getBoxes();
// { INBOX: { attribs: [], delimiter: '/', children: {...} } }
openBox(mailboxName: string, readOnly?: boolean): Promise<Mailbox>

打开用于操作的邮箱.

const mailbox = await client.openBox('INBOX');
console.log(mailbox.messages.total);  // Total message count
console.log(mailbox.messages.unseen); // Unseen message count
addBox(mailboxName: string): Promise<void>

创建新邮箱.

await client.addBox('Archive');
delBox(mailboxName: string): Promise<void>

删除邮箱.

await client.delBox('OldFolder');
renameBox(oldName: string, newName: string): Promise<void>

重命名邮箱.

await client.renameBox('OldName', 'NewName');
search(criteria: SearchCriteria[]): Promise<number[]>
search(criteria: SearchCriteria[], fetchOptions: FetchOptions): Promise<Message[]>

搜索符合给定标准的信息.

当呼叫没有 fetchOptions,返回一个 UID 数组(number[]) (中文(简体) ). 当呼叫时 fetchOptions,返回数组 Message 已获取数据的对象.

// Search for UIDs only
const uids = await client.search(['UNSEEN']);
console.log(uids); // [1, 2, 3]

// Search and fetch message data
const messages = await client.search(['UNSEEN'], { bodies: ['HEADER'] });

// Multiple criteria (AND logic)
const messages = await client.search([
  'UNSEEN',
  ['FROM', '[email protected]'],
  ['SINCE', new Date('2024-01-01')]
], { bodies: ['HEADER'] });
fetch(source: string | number[], fetchOptions: FetchOptions): Promise<Message[]>

通过 UID 获取信件 .

const messages = await client.fetch([1, 2, 3], {
  bodies: ['HEADER', 'TEXT'],
  struct: true,
  envelope: true
});
addFlags(uids: number[], flags: string[]): Promise<void>

在信件中添加旗帜 .

await client.addFlags([1, 2, 3], ['\\Seen', '\\Flagged']);
delFlags(uids: number[], flags: string[]): Promise<void>

从信件中删除旗帜 .

await client.delFlags([1, 2, 3], ['\\Seen']);
move(uids: number[], destBox: string): Promise<void>

将信件移动到另一个邮箱(复制后标记为已删除).

await client.move([1, 2, 3], 'Archive');
await client.expunge(); // Remove originals
copy(uids: number[], destBox: string): Promise<void>

复制信件到另一个邮箱 .

await client.copy([1, 2, 3], 'Backup');
expunge(): Promise<void>

永久删除标有 \Deleted 旗帜.

await client.expunge();
idle(): Promise<IdleController>

输入IDLE模式用于实时邮箱通知(RFC 217).

const idle = await client.idle();

idle.on('exists', (count) => {
  console.log(`New message count: ${count}`);
});

idle.on('expunge', (seqno) => {
  console.log(`Message ${seqno} was expunged`);
});

// Stop IDLE when done
await idle.stop();
watch(options?: { pollInterval?: number }): Promise<IdleController>

开始观看邮箱更改 。 如果支持使用IDLE,否则会回到投票.

const watcher = await client.watch({ pollInterval: 30000 });

watcher.on('exists', (count) => {
  console.log(`New message count: ${count}`);
});

await watcher.stop();
poll(): Promise<IdleNotification[]>

使用 NOOP 命令对邮箱进行修改。 没有 IDLE 支持的服务器倒置 .

const notifications = await client.poll();
for (const n of notifications) {
  if (n.type === 'exists') {
    console.log(`New message count: ${n.count}`);
  }
}
openBoxWithQresync(mailboxName, qresync, readOnly?): Promise<QresyncResult>

开通了QRESYNC的邮箱快速再同步(RFC 7162).

// Save state from previous session
const savedState = {
  uidValidity: box.uidvalidity,
  lastKnownModseq: box.highestModseq
};

// Later session - resync efficiently
const result = await client.openBoxWithQresync('INBOX', savedState);
console.log('Vanished UIDs:', result.vanished);
hasCapability(capability: string): boolean

检查服务器是否支持特定的能力 .

if (client.hasCapability('IDLE')) {
  const idle = await client.idle();
}
hasCondstore(): boolean

检查服务器是否支持 CONDSTORE 扩展( RFC 7162) 高效旗下同步.

hasQresync(): boolean

检查服务器是否支持QRESYNC扩展(RFC 7162)进行快信箱再同步.

getCapabilities(): Set<string>

返回所有服务器能力 .

refreshCapabilities(): Promise<Set<string>>

刷新并返回服务器能力 .

属性

  • isConnected: boolean - 目前客户端是否已连接
  • selectedMailbox: Mailbox | null - 目前选定的邮箱

活动

  • error - 当连接出错时被解禁
  • close - 连接关闭时被放出
client.on('error', (err) => console.error('Connection error:', err));
client.on('close', () => console.log('Connection closed'));

配置

interface ImapConfig {
  imap: {
    host: string;           // IMAP server hostname
    port?: number;          // Port (default: 993)
    user: string;           // Username
    password?: string;      // Password (for basic auth)
    xoauth2?: XOAuth2Options; // OAuth2 auth (for Gmail, Microsoft 365)
    tls?: boolean;          // Use TLS (default: true)
    tlsOptions?: TlsOptions;
    authTimeout?: number;   // Auth timeout in ms (default: 30000)
    connTimeout?: number;   // Connection timeout in ms (default: 30000)
  };
}

interface XOAuth2Options {
  user: string;             // User email address
  accessToken: string;      // OAuth2 access token
}

interface TlsOptions {
  rejectUnauthorized?: boolean;
  ca?: string | Buffer | string[] | Buffer[];
  cert?: string | Buffer;
  key?: string | Buffer;
}

OAuth2 认证 (Gmail, Microsoft 365)

对于Gmail和Microsoft 365,基本密码认证被贬值. 替换使用 OAuth2 :

// Gmail with OAuth2
const client = await ImapClient.connect({
  imap: {
    host: 'imap.gmail.com',
    port: 993,
    user: '[email protected]',
    xoauth2: {
      user: '[email protected]',
      accessToken: 'ya29.your-oauth2-access-token'
    },
    tls: true
  }
});

// Microsoft 365 with OAuth2
const client = await ImapClient.connect({
  imap: {
    host: 'outlook.office365.com',
    port: 993,
    user: '[email protected]',
    xoauth2: {
      user: '[email protected]',
      accessToken: 'eyJ0eXAiOiJKV1Q...'
    },
    tls: true
  }
});

搜索标准

支持的搜索标准 :

标准说明
'ALL'所有信件
'UNSEEN'未读信件
'SEEN'读取信件
'FLAGGED'标记信件
'UNFLAGGED'未标记的消息
'ANSWERED'已回复信件
'DELETED'删除信件
'DRAFT'电文草稿
'NEW'新消息
'RECENT'最近的消息
['FROM', string]从地址包含
['TO', string]地址包含
['CC', string]CC 地址包含
['SUBJECT', string]主题包含
['BODY', string]包含
['SINCE', Date]至今
['BEFORE', Date]日期之前
['ON', Date]日期
['LARGER', number]大于字节
['SMALLER', number]比字节小
['UID', string]UID 序列
['HEADER', field, value]页眉字段包含

获取选项

interface FetchOptions {
  bodies?: string | string[];  // Body parts to fetch
  struct?: boolean;            // Include body structure
  envelope?: boolean;          // Include envelope
  size?: boolean;              // Include size
  markSeen?: boolean;          // Mark as seen when fetching
}

机体部件( E)bodies 选项)

这个 bodies 选项接受各种格式来获取消息的不同部分:

数值说明
'HEADER'所有信件头
'HEADER.FIELDS (FROM SUBJECT DATE)'仅指定标题
'HEADER.FIELDS.NOT (BCC)'除指定外,所有信头
'TEXT'信件正文( 没有信头)
'' (空字符串)全部信息(标题+正文)
'1'第一个MIME部分
'1.2'嵌入式MIME部分(第1部分第2部分)
'1.HEADER'特定MIME部分的标题
'1.TEXT'具体多边措施部分的正文

示例用法:

// Fetch only specific headers
const messages = await client.fetch(uids, {
  bodies: ['HEADER.FIELDS (FROM SUBJECT DATE)']
});

// Fetch headers and body text
const messages = await client.fetch(uids, {
  bodies: ['HEADER', 'TEXT']
});

// Fetch entire message
const messages = await client.fetch(uids, {
  bodies: ['']
});

页眉解析

图书馆输出 a parseHeaders() 用于解析原始标题文本的工具 :

import { parseHeaders } from '@dyanet/imap';

// Parse headers from a message part
const headerPart = message.parts.find(p => p.which.includes('HEADER'));
const headers = parseHeaders(headerPart.body.toString());

// Access headers (keys are lowercase)
const subject = headers.get('subject');  // string | string[]
const from = headers.get('from');
const date = headers.get('date');

标准旗帜

  • \Seen - 信件已经读取
  • \Answered - 信件已回复
  • \Flagged - 信息被标记
  • \Deleted - 信件被标记为删除
  • \Draft - 讯息是草稿

扩展能力

库为高级功能支持了多个IMAP扩展. 使用 hasCapability() 在使用这些特性之前检查服务器支持.

IDLE (RFC 2177) (法语)

没有投票的实时邮箱通知.

if (client.hasCapability('IDLE')) {
  const idle = await client.idle();
  
  idle.on('exists', (count) => console.log(`Messages: ${count}`));
  idle.on('expunge', (seqno) => console.log(`Deleted: ${seqno}`));
  idle.on('fetch', ({ seqno, flags }) => console.log(`Flags changed: ${seqno}`));
  
  // Stop when done
  await idle.stop();
}

联系(RFC 7162)

使用 MODSEQ 值进行高效旗帜同步的有条件STORE.

if (client.hasCondstore()) {
  const mailbox = await client.openBox('INBOX');
  // mailbox.highestModseq contains the current MODSEQ value
  console.log(`Highest MODSEQ: ${mailbox.highestModseq}`);
}

QRESYNC (RFC 7162) (中文(简体) )

快速邮箱再同步 - 重接后高效同步.

if (client.hasQresync()) {
  // Save state when disconnecting
  const savedState = {
    uidValidity: mailbox.uidvalidity,
    lastKnownModseq: mailbox.highestModseq
  };
  
  // On reconnect, get only changes
  const result = await client.openBoxWithQresync('INBOX', savedState);
  
  console.log('Expunged UIDs:', result.vanished);
  console.log('Current mailbox:', result.mailbox);
}

能力检测

// Check specific capability
if (client.hasCapability('IDLE')) { /* ... */ }

// Get all capabilities
const caps = client.getCapabilities();
console.log('Server supports:', [...caps].join(', '));

// Refresh capabilities (after authentication changes)
await client.refreshCapabilities();

处理错误

库对不同的错误类别使用打入错误分类 :

import { 
  ImapError,
  ImapProtocolError,
  ImapNetworkError,
  ImapParseError,
  ImapTimeoutError 
} from '@dyanet/imap';

try {
  await client.openBox('NonExistent');
} catch (err) {
  if (err instanceof ImapProtocolError) {
    console.log('Server error:', err.serverResponse);
  } else if (err instanceof ImapNetworkError) {
    console.log('Network error:', err.host, err.port);
  } else if (err instanceof ImapTimeoutError) {
    console.log('Timeout:', err.operation, err.timeoutMs);
  }
}
错误类来源包含
ImapProtocolError服务器 NO/BAD 响应服务器响应文本, 命令
ImapNetworkError连接失败主机、 端口、 内在错误
ImapParseError答复不当无法解析的原始数据
ImapTimeoutError运行超时操作名称、暂停时间

A. 从简单移民

这个库是用来代替 Imp-simp 的:

// Before (imap-simple)
import imapSimple from 'imap-simple';
const connection = await imapSimple.connect(config);

// After (@dyanet/imap)
import { ImapClient } from '@dyanet/imap';
const connection = await ImapClient.connect(config);

配置格式和方法签名与imap-simp兼容.

试试看自己的邮箱

进来的两条路,取决于你是否想看图书馆的工作还是看一个 真实的应用程序建在它上.

📹 一个视频的行走即将到来. 在此之前,以下书面步骤 是完整的路径.

1. 实例应用软件——这是我们用它来测试的

examples/gmail-viewer/ 是一个完整的Express 应用程序,将签名输入 Gmail over OAuth2并浏览您的收件箱. 我们用它来练习 库对一个活服务器,所以这是最快的确认方法 工作结束到结束.

git clone https://github.com/dyanet/imap.git
cd imap/examples/gmail-viewer
npm install
cp .env.example .env      # then fill in the two Google values below
npm run dev               # builds and starts on http://localhost:3000
命令它会做什么
npm run dev构建然后启动( 先使用)
npm run build编译类型脚本到 dist/
npm start运行已建的 dist/server.js
npm run verify不排放类型检查

获得两个Google值. 在那个 谷歌云控台数字 : 创建( 或选择) 项目 启用 Gmail API 邮件 → 创建 证书 – OAuth 客户端 ID – Web 应用程序 • 添加 http://localhost:3000/callback 作为授权的重定向URI. 复制 客户身份和秘密进入 .env 作为 GOOGLE_CLIENT_ID 财务报告和审定财务报表 GOOGLE_CLIENT_SECRET,然后打开 http://localhost:3000 并签入.

详细情况,包括部署情况 examples/gmail-viewer/README.md。 。 。 .

关于展望: 发送时的示例应用程序是 Gmail- only —— 其 OAuth 流 被硬码到谷歌的终点。 指着Outlook意味着 在 Microsoft Entra ID 中注册一个应用程序并交换授权/托肯 URL和范围. 下面的图书馆是提供者不可知的;见下文.

2. 直接针对Gmail或Outlook的图书馆

ImapConfig 使用任何主机或密码或 XOUSTH2,所以不 需要实例应用程序来尝试邮箱.

邮件 ——最快的路线,因为Google仍然接受应用密码 为IMAP. 开启二步验证,然后在 (原始内容存档于2018-03-27). my account.google.com/appasswords数字 :

import { ImapClient } from '@dyanet/imap';

const client = new ImapClient({
  imap: {
    host: 'imap.gmail.com',
    port: 993,
    user: '[email protected]',
    password: 'your-16-char-app-password',  // not your account password
    tls: true,
  },
});

await client.connect();
const box = await client.openBox('INBOX');
console.log(`${box.messages.total} messages`);
await client.end();

展望/微软365 —— 说 应用程序密码在这里不再有效 . 微软完成了IMAP、POP和SMTP的基础认证 ; 应用程序密码依赖它,停止运行,不能是 重新生成。 OAuth2 是唯一的路径, 因此 Outlook 需要 xoauth2 相当 比起来 password数字 :

const client = new ImapClient({
  imap: {
    // Microsoft 365 / work accounts. Personal outlook.com and hotmail.com
    // mailboxes use imap-mail.outlook.com.
    host: 'outlook.office365.com',
    port: 993,
    user: '[email protected]',
    xoauth2: {
      user: '[email protected]',
      accessToken: entraAccessToken,   // from Microsoft Entra ID
    },
    tls: true,
  },
});

获取 entraAccessToken 通过在 微软环境 身份证,给予它 IMAP.AccessAsUser.All 授权,以及 运行标准授权码流。 见 微软IMAP OAuth2 指南。 。 。 .

3. 不需要邮箱

工匠们 运行此库的 MIME 和 RFC 2047 标题在浏览器中解析 – 粘贴 生头并看解码. 没有安装和账户 所需经费.

类型脚本支持

严格模式的完整类型脚本支持. 所有公共类型都导出 :

import type {
  ImapConfig,
  TlsOptions,
  Mailbox,
  MailboxTree,
  Message,
  MessagePart,
  SearchCriteria,
  FetchOptions,
  Envelope,
  BodyStructure,
  Address
} from '@dyanet/imap';

所需资源

  • 节点.js >= 20.0.0

许可证

麻省理工学院

版本与发布记录

@dyanet/imap 共发布 6 个版本,首次发布于 2025/12/23;过去 12 个月发布了 6 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.6.1latest2026/09/271 个月前
0.6.02026/08/172 个月前
0.5.22026/01/0510 个月前
0.5.12025/12/2310 个月前
0.5.02025/12/2310 个月前
0.1.02025/12/2310 个月前

关于 @dyanet/imap 的常见问题

@dyanet/imap 是什么?

一个现代零依赖性 TypeScript IMAP 客户端库 - 为 Imp- simp 和 Imp 套件所倒置

如何安装 @dyanet/imap?

在项目目录运行 npm install @dyanet/imap,或使用 pnpm add / yarn add / bun add。

@dyanet/imap 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@dyanet/imap 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@dyanet/imap 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@dyanet/imap 可以商用吗?

@dyanet/imap 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@dyanet/imap 的下载量有多少?

根据 npm 官方下载统计,@dyanet/imap 在 2026/10/13 – 2026/11/11 这 30 天内被下载 2,725 次,日均约 91 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dyanet/imap 还在维护吗?

最新版本 0.6.1 发布于 2026/09/27(1 个月前);至今共发布 6 个版本,其中过去 12 个月发布了 6 个;首次发布于 2025/12/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。