imap-sync-client
TypeScript icon, indicating that this package has built-in type declarations

1.0.1 • Public • Published

node-imap-sync-client

说明

网址: https://gitee.com/linuxmail/node-imap-sync-client

同步操作 imap 客户端, 见例子 examples

本客户端将来的版本也不考虑支持 fetch bodystructure / envelope, 请慎重选择

本imap客户端, 特点:

  • 全部命令都是 promise 风格
  • 主要用于和 IMAPD 服务器同步邮箱数据和邮件数据
  • 不支持bodystructure,envelope等, 只完整下载信件, 信件解析由其他库负责
  • 支持文件夹的创建/删除/移动(改名)
  • 支持邮件的复制/移动/删除/标记/上传
  • 支持获取文件夹下邮件UID列表
  • 各种方法返回的邮箱文件夹名字都是 Buffer

接口 interface

对象初始化 选项

interface options extends socketSyncBuffer.options {
  user: string // 用户
  pass: string // 密码
  tryStartTLS?: boolean  // 如果服务器支持就启动 STARTTLS
  startTLS?: boolean // 是否启动 STARTTLS
  cmdIdInfo?: string // imap 命令 ID 的具体内容, 一般用于向服务器表明身份
}

回调函数类型, 记录通讯协议内容

interface readWriteRecordHandler {
  (type: string, data: Buffer): void   // type: read/write
}

读取一行, 解析为一组 token

export interface readOneLineResult {
  tokens: Buffer[]
  extraDataLength: number // 最后一个token 形如: {123}
}

命令 status 结果解析

interface mboxStatus {
  messages: number
  recent: number
  uidnext: number
  uidvalidity: number
  unseen: number
}

命令 list/lsub 返回的结果按行解析

interface mboxAttrs {
  noinferiors: boolean
  noselect: boolean
  junk: boolean
  trash: boolean
  sent: boolean
  drafts: boolean
}

命令 select 返回的结果解析

interface mboxSelect {
  exists: number
  recent: number
  uidvalidity: number
  uidnext: number
  highestmodseq: number
}

文件夹信息

interface mboxInfo {
  pathname: Buffer, // 文件夹名(Buffer), 返回的文件夹名字可能不是 imap-utf-7 编码
  attrs: mboxAttrs
  status?: mboxStatus
  subscribed?: boolean
}

邮件标记

interface mailFlags {
  answered?: boolean // 是否已回复
  seen?: boolean // 是否已读
  draft?: boolean // 是否草稿
  flagged?: boolean // 是否标记(星标)
  deleted?: boolean // 是否删除
}

邮件标记 + 邮件 UID, 用于邮件列表

interface mailUidWithFlags extends mailFlags {
  uid: number
}

uidplus 扩展, 移动/复制/上传的结果

interface uidplusResult {
  uidvalidity: number,
  uid: number
}

使用方法

见例子: examples/imap.js

创建对象

const imapSyncClient = require("imap-sync-sclient")
let ic = new imapSyncClient.imapSyncClient({
  host: "127.0.0.1",
  port: 143,
  user: "test@linuxmail.cn",
  pass: "password",
  tryStartTLS: true,
})

打开连接并初始化

打开imap连接,并认证等, 使用者可以自己实现类似的方法

// 返回 null 表示网络错误, 否则返回 boolean 值, true 表示成功
async open()

发起 STARTTLS 握手

发起命令 STARTTLS, 然后开始 ssl 握手

// 返回 null 表示网络错误, 否则返回 boolean 值, true 表示成功
async cmdStartTLS();

读取welcome

// 返回 null 表示网络错误, 否则返回 Buffer
// open() 方法内会调用这个方法
async readWelcome()

命令 capability

// 执行执行命令 capability 并返回结果, 同时保存到缓存
async forceGetCapability()
// 首先从缓存中取值
async getCapability()

登录

现在只支持 login

// 返回 null 表示网络失败, 否则返回 boolean, true表示认证成功
// open() 方法会调用这个方法
async login()

命令 ID

open() 方法会调用这个方法

//  返回 null 表示网络失败, 否则返回 boolean, true表示认证成功
// idInfo 为空则使用对象初始化参数 cmdIdInfo
async cmdId(idInfo?: string)

命令 LIST/LSUB

//  返回 null 表示网络失败, 否则返回 mboxInfo[]
async getMboxList()
async getSubscribedMboxList()
// 获取文件夹全部信息(LIST + LSUB + STATUS)
async getAllMboxInfos()

命令 create, 创建文件夹

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async createMbox(pathname: string | Buffer)
// 创建文件夹, 并订阅
async createAndSubscribeMbox(pathname: string | Buffer)

命令 delete, 删除文件夹

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async deleteMbox(pathname: string | Buffer)

命令 subscribe, 订阅文件夹

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async subscribeMbox(pathname: string | Buffer)

命令 unSubscribe, 取消订阅文件夹

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async unSubscribeMbox(pathname: string | Buffer)

命令 rename, 文件夹改名

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async renameMbox(fromPathname: string | Buffer, toPathname: string | Buffer)

命令 select, 选择(打开)文件夹

// 返回 null 表示网络失败, 否则返回 mboxSelect
// 命令 select, 选择(打开) 文件夹
async forceSelectMbox(pathname: string | Buffer) {
// 如过select的文件夹不变,则直接返回成功
async selectMbox(pathname: string | Buffer) {

命令 UID MOVE, 移动邮件

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
// 一封
async moveOneMailByUid(uid: number | string, toPathname: string | Buffer, options?: {
  callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
})
// 多封
async moveMailByUid(uids: string, toPathname: string | Buffer, options?: {})

命令 MOVE, 移动邮件

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
// 一封
async moveOneMailBySn(sn: number | string, toPathname: string | Buffer, options?: {
  callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
})
// 多封
async moveMailBySn(sns: string, toPathname: string | Buffer, options?: {})

命令 UID COPY, 复制邮件

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
// 一封
async copyOneMailByUid(uid: number | string, toPathname: string | Buffer, options?: {
  callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
})
// 多封
async copyMailByUid(uids: string, toPathname: string | Buffer, options?: {})

命令 COPY, 复制邮件

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
// 一封
async copyOneMailBySn(sn: number | string, toPathname: string | Buffer, options?: {
  callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
})
// 多封
async copyMailBySn(sns: string, toPathname: string | Buffer, options?: {})

命令 UID STORE, 设置标记

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async setMailFlagByUid(uidOrUids: number | string, flags: mailFlags, set_or_unset?: boolean)
async unsetMailFlagByUid(uidOrUids: number | string, flags: mailFlags)

命令 STORE, 设置标记

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async setMailFlagBySn(snOrSns: number | string, flags: mailFlags, set_or_unset?: boolean)
async unsetMailFlagBySn(snOrSns: number | string, flags: mailFlags)

删除信件, UID

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async deleteMailByUid(uidOrUids: number | string)

删除信件

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async deleteMailBySn(snOrSns: number | string)

获取邮件列表 UID + 标记

// 返回 null 表示网络失败, 否则返回 mailUidWithFlags[]
async fetchUidListWithFlags()

通过搜索命令, 获取邮件 UID 列表

// 返回 null 表示网络失败, 否则返回 number[]

//  全部邮件
async searchAllUids()
// 全部未读邮件
async searchUnseenUids()
// 全部已回复邮件
async searchAnsweredUids()
// 全部设置了已删除标记的邮件
async searchDeletedUids()
// 全部草稿邮件
async searchDraftUids()
// 全部flagged(星标)邮件
async searchFlaggedUids()

命令 append, 上传信件

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
// callbackForMailPieceData, 多次调用, 返回上传的信件的部分数据,读够mailSize就不在执行
// options.callbackForUidplus, 如果支持 uidplus 协议, 则执行
async appendMail(mboxname: Buffer | string, mailSize: number,
  callbackForMailPieceData: { (): Promise<Buffer | null> },
  options?: {
    flags?: mailFlags
    date?: any /* string, unix-time, Date */
    callbackForUidplus?: { (r: uidplusResult): void }
  })

imap 返回结果 OK/NO/BAD

// 返回 boolean
resultIsOk()
resultIsNo()
resultIsBad()

编译字符串

escape(str: string | Buffer): string | Buffer
// 例如:
escape("a\nb\"c") => "a\\nb\"c"
// 或
escape("a\nb\"c") => {5}
a

b"c

其他

// 设置调试模式
setDebugMode(tf = true)

// 设置回调函数,记录通讯协议
setReadWriteRecordHandler(handler: readWriteRecordHandler)

// 返回协议的最后一行
getLastReadedBuffer(): Buffer

// 是否网络错误
isNetError()

// 是否逻辑错误
isLogicError()

// 是否密码错误
isPasswordError()

扩展(基础) API

通用 IMAP 命令 封装

大部分IMAP命令可以靠这个基础封装实现

// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async generalCmd(cmdArgv: (Buffer | string)[], options?: {
  callbackForUntag?: { (data: Buffer[]): Promise<void> }
  callbackForTag?: { (data: Buffer[]): Promise<void> }
  [keys: string]: any
})

例如:

async _searchUidsByFlag(flag: string) {
  let uids: number[] = []
  let res = await this.generalCmd(["UID SEARCH ", flag], {
    callbackForUntag: async (tokens: Buffer[]) => {
      let i;
      for (i = 2; i < tokens.length; i++) {
        uids.push(parseInt(tokens[i].toString()))
      }
    },
  })
  if (!res) {
    return null
  }
  return uids
}

读取行数据,并解析为 tokens

// 读一行返回,并解析为 tokens
async readOneLineTokens()
// 读取一个完整的返回, 并解析为 tokens
async readTokens()
// 解析返回结果是不是 OK/NO/BAD
parseResult(tokens: Buffer[]): boolean

读写原始socket数据

见 this.socket, 见模块 socket-sync-buffer

字符集转码

见过太多不规范的文件夹名字, 以 "研发部" 为例子

合法的(imap-utf-7): &eBRT0ZDo-
不规范的(imap-utf-7): &eBRT0D-
非法的(utf-7): 研发部
非法的(GBK): 研发部

本库作者认为, 库不可能自动正确处理这些文件夹名字的解码, 而只是返回Buffer.

不做进一步的转码工作, 以保证通过 Buffer 能正确的操作这些文件夹

而文件夹的名字要最终转为UTF-8用于显示,使用者需要自己承担乱码的风险, 建议通过库 jschardet 来自动识别字符集

下面是规范的字符集转码方法:

// 
const imapSyncClient = require("imap-sync-sclient")

// 字符集转码: imap-utf-7 => utf-8 
function imapSyncClient.imapUtf7ToUtf8(str: string | Buffer): string

// 字符集转码: utf-8 => imap-utf-7
function imapSyncClient.utf8ToImapUtf7(str: string | Buffer): string

Readme

Keywords

Package Sidebar

Install

npm i imap-sync-client

Weekly Downloads

1

Version

1.0.1

License

MIT

Unpacked Size

65.8 kB

Total Files

5

Last publish

Collaborators

  • linuxmail