
Security News
libxml2 Maintainer Ends Embargoed Vulnerability Reports, Citing Unsustainable Burden
Libxml2’s solo maintainer drops embargoed security fixes, highlighting the burden on unpaid volunteers who keep critical open source software secure.
imap-sync-client
Advanced tools
网址: https://github.com/mailhonor/node-imap-sync-client
同步操作 imap 客户端, 见例子 examples
本imap客户端, 特点:
export type ImapSyncClientOptions = {
user: string // 用户
pass: string // 密码
tryStartTLS?: boolean // 如果服务器支持就启动 STARTTLS
startTLS?: boolean // 是否启动 STARTTLS
cmdIdInfo?: string // imap 命令 ID 的具体内容, 一般用于向服务器表明身份,
// 如: '("name" "linuxmail.cn" "abc" "def")'
} & socketSyncBuffer.options
export type ReadWriteRecordHandler = (
type: string, // type: read/write
data: Buffer) => void
export type ResponseToken = {
value: Buffer,
children: ResponseToken[]
}
// 读取一行, 解析为一组 token
export type ReadOneLineResult = {
tokens: ResponseToken[],
extraDataLength: number, // 最后一个token 形如: {123}
depth: number,
}
export type MboxStatus = {
messages: number
recent: number
uidnext: number
uidvalidity: number
unseen: number
}
export type MboxAttrs = {
noinferiors: boolean
noselect: boolean
hierarchySplitor: string,
inbox: boolean
junk: boolean
trash: boolean
sent: boolean
drafts: boolean
}
export type MboxSelect = {
exists: number
recent: number
uidvalidity: number
uidnext: number
highestmodseq: number
}
export type MboxInfo = {
mboxName: Buffer, // 文件夹名(Buffer), 返回的文件夹名字可能不是 imap-utf-7 编码
mboxNameUtf8: string, // 文件夹名), 一定是 ""
attrs: MboxAttrs
status?: MboxStatus
subscribed?: boolean
}
export type MailFlags = {
answered?: boolean // 是否已回复
seen?: boolean // 是否已读
draft?: boolean // 是否草稿
flagged?: boolean // 是否标记(星标)
deleted?: boolean // 是否删除
}
export type MailUidWithFlags = {
uid: number
} & MailFlags
export type UidplusResult = {
uidvalidity: number,
uid: number
}
export type EnvelopeAddress = {
name: Buffer;
nameUtf8: string;
address: string;
}
// 为null, 表示字段不存在
export type EnvelopeAttrs = {
uid: number,
size: number,
date: string,
subject: Buffer,
subjectUtf8: string,
from: EnvelopeAddress | null,
sender: EnvelopeAddress | null,
to: EnvelopeAddress[] | null,
cc: EnvelopeAddress[] | null,
bcc: EnvelopeAddress[] | null,
replyTo: EnvelopeAddress[] | null,
inReplyTo: string,
messageId: string,
flags: MailFlags,
}
export type BodyStructure = {
textMimes: MimeNode[], // 文本可读可显示的节点
showMimes: MimeNode[], // 如上, 且首先需要显示的
attachmentMimes: MimeNode[], // 附件类节点
topMime: MimeNode,
}
export type MailInfo = {
} & BodyStructure & Envelope
见例子: 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, 然后开始 ssl 握手
// 返回 null 表示网络错误, 否则返回 boolean 值, true 表示成功
async cmdStartTLS();
// 返回 null 表示网络错误, 否则返回 Buffer
// open() 方法内会调用这个方法
async readWelcome()
// 执行执行命令 capability 并返回结果, 同时保存到缓存
async forceGetCapability()
// 首先从缓存中取值
async getCapability()
现在只支持 login
// 返回 null 表示网络失败, 否则返回 boolean, true表示认证成功
// open() 方法会调用这个方法
async login()
open() 方法会调用这个方法
// 返回 null 表示网络失败, 否则返回 boolean, true表示认证成功
// idInfo 为空则使用对象初始化参数 cmdIdInfo
async cmdId(idInfo?: string)
// 返回 null 表示网络失败, 否则返回 mboxInfo[]
async getMboxList()
async getSubscribedMboxList()
// 获取文件夹全部信息(LIST + LSUB + STATUS)
async getAllMboxInfos()
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async createMbox(pathname: string | Buffer)
// 创建文件夹, 并订阅
async createAndSubscribeMbox(pathname: string | Buffer)
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async deleteMbox(pathname: string | Buffer)
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async subscribeMbox(pathname: string | Buffer)
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async unSubscribeMbox(pathname: string | Buffer)
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async renameMbox(fromPathname: string | Buffer, toPathname: string | Buffer)
// 返回 null 表示网络失败, 返回 false 表示不存在, 否则返回 mboxSelect
// 命令 select, 选择(打开) 文件夹
async forceSelectMbox(pathname: string | Buffer)
// 如过select的文件夹不变,则直接返回成功
async selectMbox(pathname: string | Buffer)
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
// 一封
async moveOneMail(uid: number | string, toPathname: string | Buffer, options?: {
callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
})
// 多封
async moveMail(uids: string, toPathname: string | Buffer, options?: {})
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
// 一封
async copyOneMail(uid: number | string, toPathname: string | Buffer, options?: {
callbackForUidplus?: { (r: { uidvalidity: number, uid: number }): void }
})
// 多封
async copyMail(uids: string, toPathname: string | Buffer, options?: {})
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async setMailFlag(uidOrUids: number | string, flags: mailFlags, set_or_unset?: boolean)
async unsetMailFlag(uidOrUids: number | string, flags: mailFlags)
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async deleteMail(uidOrUids: number | string)
// 返回 null 表示网络失败, 否则返回 mailUidWithFlags[]
async fetchUidListWithFlags()
// 返回 null 表示网络失败, 否则返回 number[]
// 全部邮件
async searchAllUids()
// 全部未读邮件
async searchUnseenUids()
// 全部已回复邮件
async searchAnsweredUids()
// 全部设置了已删除标记的邮件
async searchDeletedUids()
// 全部草稿邮件
async searchDraftUids()
// 全部flagged(星标)邮件
async searchFlaggedUids()
// 返回 null 表示网络失败, 否则返回 UID 数组
// querys: 形如:
// CHARSET UTF-8 FLAGGED SINCE 1-Feb-2001
// SUBJECT "Linux is good"
// CC "admin@a.com" TEXT abc
async searchMail(querys: string)
// 返回 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 }
})
// 返回 null 表示网络失败, false 表示 信件不存在
async fetchEnvelope(uid: string | number): Promise<EnvelopeAttrs | false | null>
async fetchMailStructure(uid: number | string): Promise<BodyStructure | false | null>
async fetchMailInfo(uid: number | string): Promise<MailInfo | false | null>;
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async fetchMailData(uid: number,
callbackForMailPieceData: { (pieceData: Buffer): Promise<boolean> }, // 一部分一部分的返回信件内容,
options?: {
partial?: {
offset: number,
length: number,
},
}
)
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async fetchMailHeader(uid: number,
callbackForMailPieceData: { (pieceData: Buffer): Promise<boolean> }, // 一部分一部分的返回信件内容,
options?: {
partial?: {
offset: number,
length: number,
},
}
)
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async fetchMimeDataBySection(uid: number | string,
section: string,
callbackForMailPieceData: { (pieceData: Buffer): Promise<boolean> },
options?: {
partial?: {
offset: number,
length: number,
},
})
// 返回 null 表示网络失败, 否则返回 boolean, true表示成功
async fetchMimeHeaderBySection(uid: number | string,
section: string,
callbackForMailPieceData: { (pieceData: Buffer): Promise<boolean> },
options?: {
partial?: {
offset: number,
length: number,
},
})
// 返回 boolean
resultIsOk()
resultIsNo()
resultIsBad()
setMaybeHaveNewMailHandler(handler: (pathname: Buffer) => any)
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()
大部分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
async readOneLineTokens()
// 读取一个完整的返回, 并解析为 tokens
async readTokens()
// 解析返回结果是不是 OK/NO/BAD
parseResult(tokens: Buffer[]): boolean
见 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
FAQs
imap sync client, always promise
The npm package imap-sync-client receives a total of 12 weekly downloads. As such, imap-sync-client popularity was classified as not popular.
We found that imap-sync-client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Libxml2’s solo maintainer drops embargoed security fixes, highlighting the burden on unpaid volunteers who keep critical open source software secure.
Research
Security News
Socket researchers uncover how browser extensions in trusted stores are used to hijack sessions, redirect traffic, and manipulate user behavior.
Research
Security News
An in-depth analysis of credential stealers, crypto drainers, cryptojackers, and clipboard hijackers abusing open source package registries to compromise Web3 development environments.