node imap-sync-client: 一款 node 环境, IMAP 同步客户端库

打印 上一主题 下一主题

主题 892|帖子 892|积分 2676

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

对象初始化 选项
  1. interface ImapSyncClientOptions extends socketSyncBuffer.options {
  2.   user: string // 用户
  3.   pass: string // 密码
  4.   tryStartTLS?: boolean  // 如果服务器支持就启动 STARTTLS
  5.   startTLS?: boolean // 是否启动 STARTTLS
  6.   cmdIdInfo?: string // imap 命令 ID 的具体内容, 一般用于向服务器表明身份
  7. }
复制代码
回调函数类型, 记录通讯协议内容
  1. interface ReadWriteRecordHandler {
  2.   (type: string, data: Buffer): void   // type: read/write
  3. }
复制代码
读取一行, 解析为一组 token
  1. export interface ReadOneLineResult {
  2.   tokens: Buffer[]
  3.   extraDataLength: number // 最后一个token 形如: {123}
  4. }
复制代码
命令 status 结果解析
  1. interface MboxStatus {
  2.   messages: number
  3.   recent: number
  4.   uidnext: number
  5.   uidvalidity: number
  6.   unseen: number
  7. }
复制代码
命令 list/lsub 返回的结果按行解析
  1. interface MboxAttrs {
  2.   noinferiors: boolean
  3.   noselect: boolean
  4.   junk: boolean
  5.   trash: boolean
  6.   sent: boolean
  7.   drafts: boolean
  8. }
复制代码
命令 select 返回的结果解析
  1. interface MboxSelect {
  2.   exists: number
  3.   recent: number
  4.   uidvalidity: number
  5.   uidnext: number
  6.   highestmodseq: number
  7. }
复制代码
文件夹信息
  1. interface MboxInfo {
  2.   pathname: Buffer, // 文件夹名(Buffer), 返回的文件夹名字可能不是 imap-utf-7 编码
  3.   mboxNameUtf8: string, // 文件夹名), 一定是 ""
  4.   attrs: mboxAttrs
  5.   status?: mboxStatus
  6.   subscribed?: boolean
  7. }
复制代码
邮件标志
  1. interface MailFlags {
  2.   answered?: boolean // 是否已回复
  3.   seen?: boolean // 是否已读
  4.   draft?: boolean // 是否草稿
  5.   flagged?: boolean // 是否标记(星标)
  6.   deleted?: boolean // 是否删除
  7. }
复制代码
邮件标志 + 邮件 UID, 用于邮件列表
  1. interface MailUidWithFlags extends mailFlags {
  2.   uid: number
  3. }
复制代码
uidplus 扩展, 移动/复制/上传的结果
  1. interface UidplusResult {
  2.   uidvalidity: number,
  3.   uid: number
  4. }
复制代码
使用方法

见例子: examples/imap.js
创建对象
  1. const imapSyncClient = require("imap-sync-sclient")
  2. let ic = new imapSyncClient.imapSyncClient({
  3.   host: "127.0.0.1",
  4.   port: 143,
  5.   user: "test@linuxmail.cn",
  6.   pass: "password",
  7.   tryStartTLS: true,
  8. })
复制代码
打开毗连并初始化

打开imap毗连,并认证等, 使用者可以自己实现类似的方法
  1. // 返回 null 表示网络错误, 否则返回 boolean 值, true 表示成功
  2. async open()
复制代码
发起 STARTTLS 握手

发起命令 STARTTLS, 然后开始 ssl 握手
  1. // 返回 null 表示网络错误, 否则返回 boolean 值, true 表示成功
  2. async cmdStartTLS();
复制代码
读取welcome
  1. // 返回 null 表示网络错误, 否则返回 Buffer
  2. // open() 方法内会调用这个方法
  3. async readWelcome()
复制代码
命令 capability
  1. // 执行执行命令 capability 并返回结果, 同时保存到缓存
  2. async forceGetCapability()
  3. // 首先从缓存中取值
  4. async getCapability()
复制代码
登录

现在只支持 login
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示认证成功
  2. // open() 方法会调用这个方法
  3. async login()
复制代码
命令 ID

open() 方法会调用这个方法
  1. //  返回 null 表示网络失败, 否则返回 boolean, true表示认证成功
  2. // idInfo 为空则使用对象初始化参数 cmdIdInfo
  3. async cmdId(idInfo?: string)
复制代码
命令 LIST/LSUB
  1. //  返回 null 表示网络失败, 否则返回 mboxInfo[]
  2. async getMboxList()
  3. async getSubscribedMboxList()
  4. // 获取文件夹全部信息(LIST + LSUB + STATUS)
  5. async getAllMboxInfos()
复制代码
命令 create, 创建文件夹
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async createMbox(pathname: string | Buffer)
  3. // 创建文件夹, 并订阅
  4. async createAndSubscribeMbox(pathname: string | Buffer)
复制代码
命令 delete, 删除文件夹
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async deleteMbox(pathname: string | Buffer)
复制代码
命令 subscribe, 订阅文件夹
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async subscribeMbox(pathname: string | Buffer)
复制代码
命令 unSubscribe, 取消订阅文件夹
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async unSubscribeMbox(pathname: string | Buffer)
复制代码
命令 rename, 文件夹改名
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async renameMbox(fromPathname: string | Buffer, toPathname: string | Buffer)
复制代码
命令 select, 选择(打开)文件夹
  1. // 返回 null 表示网络失败, 返回 false 表示不存在, 否则返回 mboxSelect
  2. // 命令 select, 选择(打开) 文件夹
  3. async forceSelectMbox(pathname: string | Buffer) {
  4. // 如过select的文件夹不变,则直接返回成功
  5. async selectMbox(pathname: string | Buffer) {
复制代码
命令 UID MOVE, 移动邮件
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. // 一封
  3. async moveOneMailByUid(uid: number | string, toPathname: string | Buffer, options?: {
  4.   callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
  5. })
  6. // 多封
  7. async moveMailByUid(uids: string, toPathname: string | Buffer, options?: {})
复制代码
命令 MOVE, 移动邮件
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. // 一封
  3. async moveOneMailBySn(sn: number | string, toPathname: string | Buffer, options?: {
  4.   callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
  5. })
  6. // 多封
  7. async moveMailBySn(sns: string, toPathname: string | Buffer, options?: {})
复制代码
命令 UID COPY, 复制邮件
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. // 一封
  3. async copyOneMailByUid(uid: number | string, toPathname: string | Buffer, options?: {
  4.   callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
  5. })
  6. // 多封
  7. async copyMailByUid(uids: string, toPathname: string | Buffer, options?: {})
复制代码
命令 COPY, 复制邮件
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. // 一封
  3. async copyOneMailBySn(sn: number | string, toPathname: string | Buffer, options?: {
  4.   callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
  5. })
  6. // 多封
  7. async copyMailBySn(sns: string, toPathname: string | Buffer, options?: {})
复制代码
命令 UID STORE, 设置标志
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async setMailFlagByUid(uidOrUids: number | string, flags: mailFlags, set_or_unset?: boolean)
  3. async unsetMailFlagByUid(uidOrUids: number | string, flags: mailFlags)
复制代码
命令 STORE, 设置标志
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async setMailFlagBySn(snOrSns: number | string, flags: mailFlags, set_or_unset?: boolean)
  3. async unsetMailFlagBySn(snOrSns: number | string, flags: mailFlags)
复制代码
删除信件, UID
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async deleteMailByUid(uidOrUids: number | string)
复制代码
删除信件
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async deleteMailBySn(snOrSns: number | string)
复制代码
获取邮件列表 UID + 标志
  1. // 返回 null 表示网络失败, 否则返回 mailUidWithFlags[]
  2. async fetchUidListWithFlags()
复制代码
通过搜索命令, 获取邮件 UID 列表
  1. // 返回 null 表示网络失败, 否则返回 number[]
  2. //  全部邮件
  3. async searchAllUids()
  4. // 全部未读邮件
  5. async searchUnseenUids()
  6. // 全部已回复邮件
  7. async searchAnsweredUids()
  8. // 全部设置了已删除标记的邮件
  9. async searchDeletedUids()
  10. // 全部草稿邮件
  11. async searchDraftUids()
  12. // 全部flagged(星标)邮件
  13. async searchFlaggedUids()
复制代码
命令 append, 上传信件
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. // callbackForMailPieceData, 多次调用, 返回上传的信件的部分数据,读够mailSize就不在执行
  3. // options.callbackForUidplus, 如果支持 uidplus 协议, 则执行
  4. async appendMail(mboxname: Buffer | string, mailSize: number,
  5.   callbackForMailPieceData: { (): Promise<Buffer | null> },
  6.   options?: {
  7.     flags?: mailFlags
  8.     date?: any /* string, unix-time, Date */
  9.     callbackForUidplus?: { (r: uidplusResult): void }
  10.   })
复制代码
imap 返回结果 OK/NO/BAD
  1. // 返回 boolean
  2. resultIsOk()
  3. resultIsNo()
  4. resultIsBad()
复制代码
也许服务器有新的信件, 回调
  1. setMaybeHaveNewMailHandler(handler: (pathname: Buffer) => any)
复制代码
编译字符串
  1. escape(str: string | Buffer): string | Buffer
  2. // 例如:
  3. escape("a\nb"c") => "a\\nb"c"
  4. // 或
  5. escape("a\nb"c") => {5}
  6. a
  7. b"c
复制代码
其他
  1. // 设置调试模式
  2. setDebugMode(tf = true)
  3. // 设置回调函数,记录通讯协议
  4. setReadWriteRecordHandler(handler: readWriteRecordHandler)
  5. // 返回协议的最后一行
  6. getLastReadedBuffer(): Buffer
  7. // 是否网络错误
  8. isNetError()
  9. // 是否逻辑错误
  10. isLogicError()
  11. // 是否密码错误
  12. isPasswordError()
复制代码
扩展(基础) API

通用 IMAP 命令 封装

大部分IMAP命令可以靠这个基础封装实现
  1. // 返回 null 表示网络失败, 否则返回 boolean, true表示成功
  2. async generalCmd(cmdArgv: (Buffer | string)[], options?: {
  3.   callbackForUntag?: { (data: Buffer[]): Promise<void> }
  4.   callbackForTag?: { (data: Buffer[]): Promise<void> }
  5.   [keys: string]: any
  6. })
复制代码
比方:
  1. async _searchUidsByFlag(flag: string) {
  2.   let uids: number[] = []
  3.   let res = await this.generalCmd(["UID SEARCH ", flag], {
  4.     callbackForUntag: async (tokens: Buffer[]) => {
  5.       let i;
  6.       for (i = 2; i < tokens.length; i++) {
  7.         uids.push(parseInt(tokens[i].toString()))
  8.       }
  9.     },
  10.   })
  11.   if (!res) {
  12.     return null
  13.   }
  14.   return uids
  15. }
复制代码
读取行数据,并解析为 tokens
  1. // 读一行返回,并解析为 tokens
  2. async readOneLineTokens()
  3. // 读取一个完整的返回, 并解析为 tokens
  4. async readTokens()
  5. // 解析返回结果是不是 OK/NO/BAD
  6. parseResult(tokens: Buffer[]): boolean
复制代码
读写原始socket数据

见 this.socket, 见模块 socket-sync-buffer
字符集转码

见过太多不规范的文件夹名字, 以 "研发部" 为例子
  1. 合法的(imap-utf-7): &eBRT0ZDo-
  2. 不规范的(imap-utf-7): &eBRT0D-
  3. 非法的(utf-7): 研发部
  4. 非法的(GBK): 研发部
复制代码
本库作者以为, 库不可能自动正确处置惩罚这些文件夹名字的解码, 而只是返回Buffer.
不做进一步的转码工作, 以保证通过 Buffer 能正确的操纵这些文件夹
而文件夹的名字要最终转为UTF-8用于显示,使用者必要自己承担乱码的风险, 发起通过库 jschardet 来自动辨认字符集
下面是规范的字符集转码方法:
  1. //
  2. const imapSyncClient = require("imap-sync-sclient")
  3. // 字符集转码: imap-utf-7 => utf-8
  4. function imapSyncClient.imapUtf7ToUtf8(str: string | Buffer): string
  5. // 字符集转码: utf-8 => imap-utf-7
  6. function imapSyncClient.utf8ToImapUtf7(str: string | Buffer): string
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

锦通

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表