@ bumail/ imap (帮助)
Bun 的 IMAP 服务器, 打开 Bun.listen: IMAP4rev2(RFC 9051),与
IMAP4rev1客户端也服务;STATLS或隐含的TLS;LOGIN和
AUTHENTICATE PLAIN,只加密一次;IDLE,MOVE,UIDPLUS,CONDSTORE,QRESYNC,BINARY,Special-USE,
名单 -- -- 电子研究和文学+。 它服务于任何邮件
@bumail/store MailStore,并读取信件
@bumail/mime。命令线客户端( curl, Python )
imaplib, (中文(简体) ), imapclient以可重复的文字与它相对应;
雷鸟和苹果邮报通过人工检查. 运行,没有,是
编辑 界面。 。 。 .
bun add @bumail/imap @bumail/store @bumail/mime
@bumail/store 财务报告和审定财务报表 @bumail/mime 是同等端: 安装您的应用程序版本
用户. typescript 是一个可选的对等点,用于类型.
143街和993街的店铺
这个 authenticate 钩子是用户登录的方式:它获得证书和
回答要服务的存储账户的id,或 null 拒绝。 没错
只通过 TLS 询问 .
import { createImapServer } from '@bumail/imap';
import type { ImapServerOptions } from '@bumail/imap';
import { MemoryMailStore } from '@bumail/store';
const store = new MemoryMailStore();
const alice = await store.createAccount('[email protected]');
await store.createMailbox(alice.id, { name: 'INBOX', role: 'inbox' });
await store.createMailbox(alice.id, { name: 'Sent', role: 'sent' });
await store.createMailbox(alice.id, { name: 'Archive', role: 'archive' });
const passwords = new Map([['alice', await Bun.password.hash('correct horse')]]);
const accounts = new Map([['alice', alice.id]]);
const options: ImapServerOptions = {
hostname: 'imap.example.com',
store,
tls: {
key: await Bun.file('/etc/ssl/imap.example.com.key').text(),
cert: await Bun.file('/etc/ssl/imap.example.com.crt').text(),
},
async authenticate({ username, password }) {
const hash = passwords.get(username);
if (!hash || !(await Bun.password.verify(password, hash))) return null;
return accounts.get(username) ?? null;
},
};
// 143: clear at first, STARTTLS before logging in.
await createImapServer(options).listen({ port: 143 });
// 993: TLS from the first byte (RFC 8314), what most clients pick.
await createImapServer({ ...options, implicitTls: true }).listen({ port: 993 });
寄入商店的邮件(截至 @bumail/smtp是因为 onData达到
iDLE中的客户端 idleInterval 秒(默认为10个)。 打电话
server.notify(accountId) 送货后立即到达.
有雷鸟试一试
- 用 Thunderbird 信任的证书运行上方的服务器
本地尝试,一个自签名的
localhost,接受雷鸟的 安全例外 当它问. - 账户设置 – 账户动作 – 添加邮件账户,则 手动配置。 。 。 .
- 来电: IMAP, 主机
localhost端口993与 SSL/TLS 系统,或143与 削减; 认证 普通密码; 用户名alice。 。 。 . - 请检查date=中的日期值 (帮助) INBOX, Sent and Archive with their special use 角色,读取消息,标记被读取,并移动到存档.
Apple Mail 相同:IMAP,端口993, 使用 TLS/ SSL, (中文(简体) ), 密码 认证。 也没有为0.5.0运行;见 界面 要检查什么.
限制
| 选项 | 默认 | |
|---|---|---|
maxConnections | 1 000个 | 再来一次 * BYE [UNAVAILABLE] Too many connections, try later |
maxMessageSize | 25个小米B | 最大附录,宣布为 APPENDLIMIT;流入商店,从未持有 |
maxLiteralSize | 64 基贝 | 任何其他命令的最大字节 |
timeout | 1800 s (英语) | 服务器挂起前秒闲置; 至少 1800 (RFC 9051 §5.4) |
loginTimeout | 60岁s | 从问候到登录 不论客户寄出多少 |
handshakeTimeout | 10 s (简体中文) | 从TCP连接到TLS握手结束 proxyProtocol,对于一个信任的代理机头;通过它,套接字关闭 |
idleInterval | 10 s (简体中文) | 两人在IDLE期间看店 |
hookTimeout | 60岁s | 页:1 authenticate 解决 |
maxSearchIndex | 10 000人 | 当商店在搜索存在之前持有一些存储时, 其字节中有一个 SEARCH 索引 |
每个计时器最多2 147 483秒,什么 setTimeout 等会儿 A 类
命令行最多为64 KiB,最多为32升,列表或
搜索密钥嵌入最多 32 个深; 在登录前, 最多2升
每人一基贝. 一个邮箱的名字最多有32级和1024个字符
(每等255个),最多16个图案的列表,最多32个TEXT的SEARCH或
车钥匙 A 类
序列设置, 例如 1:4294967295 决不会
扩大。 一个停止阅读的客户端仍然挂断在
loginTimeout 或者说 timeout,并还原其位置
maxConnections 一次; 没有排队, 它仍然读到
BYE,然后一个干净的结束,每当它再次读.
在隐含的 TLS 上,套接字占据其位置 maxConnections 从
TCP连接上,在握手前, 关闭,没有字,
handshakeTimeout 连接未完成的秒后;
问候,或 BYE 一个完整的服务器,等待握手。 这么说吧
连接且从未发送客户端 Hello 的套接字无法填充服务器 :
await createImapServer({ ...options, implicitTls: true, handshakeTimeout: 10 }).listen({ port: 993 });
不重启而更新证书
setTls 需要更新的密钥和证书:下一次STARTLS升级或
隐含的 TLS 连接使用它们, 而已打开的会话保留
他们有TLS。 双对先读后检查; 无法使用
拒绝方式 INVALID_OPTION 和旧对子继续使用.
// After certbot, Traefik or an ACME client wrote new files:
await server.setTls({
key: Bun.file('/etc/ssl/imap.example.com.key'),
cert: Bun.file('/etc/ssl/imap.example.com.crt'),
});
在每个持有一对的服务器上调用(143和993为2个). 这个 指南 说它如何在每一种港口工作.
TCP 代理服务器后面
TCP代理,如Traefik TCP路由器或HAProxy,隐藏客户端:
服务器查看代理地址。 与 proxyProtocol,代词
列入清单 trusted 首先发送 PROXY 协议头( 第 1 或 2 版) ,
财务报告和审定财务报表 session.remoteAddress,用于 authenticate 财务报告和审定财务报表 onError,这是
又是客户地址 默认关闭.
// The proxy at 10.0.0.5 sends a PROXY header; anyone else is served as before.
const proxyProtocol = { trusted: ['10.0.0.5'] };
await createImapServer({ ...options, proxyProtocol }).listen({ port: 143 });
await createImapServer({ ...options, implicitTls: true, proxyProtocol }).listen({ port: 993 });
信任的代理服务器必须在内部发送有效的信头 handshakeTimeout,或
它的连接在没有单词的情况下被重置 。 代理通过 TLS :
993上,服务器仍然持有证书。 这个
指南
拥有Traefik配置和每个案件.
陷阱
- LOGIN仅在TLS之后. 在明确的连接上,服务器广告
LOGINDISABLED和答案NO [PRIVACYREQUIRED]改为LOGIN 和 AUTHENTICATE 不读密码.tls需要这样做 理由; 无法清晰登录 . - 通讯和通讯 (RFC 7162): (法语)
ENABLE CONDSTORE, (中文(简体) ),HIGHESTMODSEQ, (中文(简体) ),FETCH与MODSEQ财务报告和审定财务报表CHANGEDSINCE, (中文(简体) ),STORE与UNCHANGEDSINCE(单位:千美元)OK [MODIFIED …]命名它留下的消息) 财务报告和审定财务报表SEARCH MODSEQ。使用 modeseq 命令使它能够,并且MODSEQ财务报告和审定财务报表UID然后进入每一个 FETCH 告诉旗帜.ENABLE QRESYNC制造VANISHED替换EXPUNGE用于连接,以及SELECT INBOX (QRESYNC (<uidvalidity> <modseq> [<known UIDs> [(<seq> <uids>)]]))财务报告和审定财务报表UID FETCH … (CHANGEDSINCE n VANISHED)回复VANISHED (EARLIER){\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}从商店的记忆中 清除,或者,当它不再记得 至今,每个已知的UID 邮箱缺乏。 没有任何人被告知没有首先要求这样做. - 比利时 (RFC 3516): (法语)
FETCH BINARY[1.2]<0.1024>, (中文(简体) ),BINARY.PEEK[…]财务报告和审定财务报表BINARY.SIZE[…]以树叶为基部64或可引用打印 由服务器解码, 部分计数解码字节; 有 NUL 的数据 当作字面上的8,~{n},附录为~{n}或者说~{n+}8-位内容( NUL 为NO [UNKNOWN-CTE]) (中文(简体) ).BINARY套装\Seen, (中文(简体) ),BINARY.PEEK没有。 一个 编码服务器无法解码NO [UNKNOWN-CTE]; 多块或多块message/rfc822实值NO [CANNOT]解码是流的,从未被持有. - Append 线程其消息: 标题(最多64 KiB)为 字符串中, 因此一个回覆会加入其父线程; 一个较长的页眉 启动它自己的线程.
- 新的 UIDPLUS 名称 (RFC 4315):附录答复
[APPENDUID <uidvalidity> <uid>],COPY和UID COPY回答[COPYUID <uidvalidity> <source UIDs> <new UIDs>]移动说 相同的无标记OK目 录(续)EXPUNGE答复(RFC 6851) (第4.3节)。 同时删除的另一客户端的信息被排除于两者之外 设定, 保持步态 . - SEARCH是商店的,在解码文本上.
BODY匹配已解码 电文的文本部分(base64,可引用打印和 字符集被撤销, HTML 读作文本, 附件被忽略)和TEXT那个 和信件的每个解码头值, 两者都无大小写. 天数 (单位:千美元)BEFORE, (中文(简体) ),ON, (中文(简体) ),SINCE, (中文(简体) ),SENT*)是协调世界时的天数;没有Date日期为抵达SENT*。搜索前存储的信息 存在是由第一个需要它的SEARCH索引的,maxSearchIndex时间 时间; 过去的命令是NO [UNAVAILABLE]数字 : 重试, 或运行bumail store index一次 一次吗 附录索引其信息. - 最后一个消息的序列号是
BAD, (中文(简体) ), 作为 RFC 9051 §6.4.4说;一个UID设置,没有消息的名称不是. - 登录前,一个字数最多为 1 KiB, 随便啦
maxLiteralSize说 密码比那还要长 通过AUTHENTICATE PLAIN. - 移动到选中的邮箱中可以, 且不会改变 : 没有
EXPUNGE同样的UID. trusted列出代理,没有其他. 列出的对等点可以 要求任何客户地址。 从不列出一个范围客户端连接, 也不要0.0.0.0/0在公共端口上:trusted: ['10.0.0.5']。 。 。 .
API 密码
| 导出 | |
|---|---|
createImapServer(options) | 服务器; 丢出一个 ImapError (单位:千美元)INVALID_OPTION) 在一个糟糕的选择 |
ImapServer | listen({ port, hostname? }),解决了束缚 { port, hostname } (一次;再次,甚至在第一次解决之前,就抛出) ALREADY_LISTENING; 在默认 TLS 上, 键或证书不能读取或使用抛出 INVALID_OPTION, (中文(简体) ), setTls({ key, cert }) (用于新STARTLS升级的更新配对和新的隐含的TLS连接;开放会话保留它们的配对;无法使用的配对 INVALID_OPTION 旧的将永居其中, stop(closeConnections?) (单位:千美元)true 挂在每一个客户端, 在STARTLS之后, notify(accountId) 为了唤醒账户的IDLE会话, connections,打开的连接数 |
ImapServerOptions | hostname, (中文(简体) ), store, (中文(简体) ), tls, (中文(简体) ), implicitTls, (中文(简体) ), authenticate,上述限制, proxyProtocol, (中文(简体) ), onError |
ImapSession | 什麽 authenticate 财务报告和审定财务报表 onError 接收: id, (中文(简体) ), remoteAddress, (中文(简体) ), secure, (中文(简体) ), user, (中文(简体) ), accountId,以及 data 为了你自己的国家 |
AuthResult | 什麽 authenticate 答案:账户编号,或 null 编号 : undefined 拒绝 |
Credentials | 什麽 authenticate 接收 : mechanism (单位:千美元)LOGIN 或者说 PLAIN, (中文(简体) ), username, (中文(简体) ), password, (中文(简体) ), authorizationId? |
TlsOptions | key 财务报告和审定财务报表 cert,作为 Bun.listen 拿着 |
ProxyProtocolOptions | trusted: 读取 PROXY 标题的代理地址 IPv4 和 IPv6 地址和 CIDR |
ImapError, (中文(简体) ), ImapErrorCode | code数字 : INVALID_OPTION, (中文(简体) ), ALREADY_LISTENING, (中文(简体) ), STOPPED 联合国 stop() 来过之前 listen (已解决) HOOK_TIMEOUT,哪个 onError 获得 |
encodeUtf7(name), (中文(简体) ), decodeUtf7(name) | 邮箱名来自修改过的UTF-7(RFC 3501 § 5.1.3),因为IMAP4rev1客户端会写 |
文档
- 指数:各页,何时读出.
- 指南: 会话,每个命令,存储映射到IMAP,IDLE和
notify,运行在 TCP 代理机后, RFCs 跟踪和没有. - 解决问题:每一个错误,以及回复的客户端按其准确的文字报告,分为配置,登录和连接(包含一个代理),语法,邮箱和消息.
- 间接: 哪些客户端运行于服务器( curl,
imaplib, (中文(简体) ),imapclient他们查过了 雷鸟和苹果邮报没有运行. - 路线图:什么是未来,什么是没有计划的.
许可证
麻省理工学院