react-native-email-imap-smtp 0.3.30 → 0.3.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +1 -1
  2. package/android/src/main/java/com/margelo/nitro/emailimapsmtp/EmailImapSmtp.kt +199 -114
  3. package/lib/module/native.js +2 -1
  4. package/lib/module/native.js.map +1 -1
  5. package/lib/typescript/server/src/imapHandler.d.ts +5 -0
  6. package/lib/typescript/server/src/imapHandler.d.ts.map +1 -1
  7. package/lib/typescript/server/src/index.d.ts.map +1 -1
  8. package/lib/typescript/server/src/smtpHandler.d.ts.map +1 -1
  9. package/lib/typescript/src/EmailImapSmtp.nitro.d.ts +4 -0
  10. package/lib/typescript/src/EmailImapSmtp.nitro.d.ts.map +1 -1
  11. package/lib/typescript/src/native.d.ts.map +1 -1
  12. package/lib/typescript/src/types.d.ts +8 -0
  13. package/lib/typescript/src/types.d.ts.map +1 -1
  14. package/nitrogen/generated/android/c++/JConnectionConfig.hpp +7 -3
  15. package/nitrogen/generated/android/c++/JSmtpServerInfo.hpp +8 -3
  16. package/nitrogen/generated/android/c++/JVariant_ImapServerInfo_SmtpServerInfo.hpp +1 -0
  17. package/nitrogen/generated/android/kotlin/com/margelo/nitro/emailimapsmtp/ConnectionConfig.kt +9 -4
  18. package/nitrogen/generated/android/kotlin/com/margelo/nitro/emailimapsmtp/SmtpServerInfo.kt +9 -4
  19. package/nitrogen/generated/ios/EmailImapSmtp-Swift-Cxx-Bridge.hpp +15 -15
  20. package/nitrogen/generated/ios/swift/ConnectionConfig.swift +20 -2
  21. package/nitrogen/generated/ios/swift/SmtpServerInfo.swift +19 -1
  22. package/nitrogen/generated/shared/c++/ConnectionConfig.hpp +6 -2
  23. package/nitrogen/generated/shared/c++/SmtpServerInfo.hpp +7 -2
  24. package/package.json +1 -1
  25. package/server/lib/imapHandler.d.ts +5 -0
  26. package/server/lib/imapHandler.d.ts.map +1 -1
  27. package/server/lib/imapHandler.js +247 -77
  28. package/server/lib/imapHandler.js.map +1 -1
  29. package/server/lib/index.d.ts.map +1 -1
  30. package/server/lib/index.js +24 -9
  31. package/server/lib/index.js.map +1 -1
  32. package/server/lib/smtpHandler.d.ts.map +1 -1
  33. package/server/lib/smtpHandler.js +76 -8
  34. package/server/lib/smtpHandler.js.map +1 -1
  35. package/server/package-lock.json +1 -0
  36. package/server/package.json +1 -0
  37. package/server/src/imapHandler.ts +273 -76
  38. package/server/src/imapflow.d.ts +31 -0
  39. package/server/src/index.ts +50 -16
  40. package/server/src/smtpHandler.ts +310 -242
  41. package/src/EmailImapSmtp.nitro.ts +4 -0
  42. package/src/native.ts +1 -0
  43. package/src/types.ts +8 -0
@@ -1,242 +1,310 @@
1
- // ============================================================
2
- // SMTP 代理处理器 — 基于 nodemailer
3
- // ============================================================
4
-
5
- import nodemailer from 'nodemailer';
6
- import { v4 as uuidv4 } from 'uuid';
7
-
8
- // ─── 类型 ───────────────────────────────────────────────────
9
-
10
- interface SmtpSession {
11
- transporter: nodemailer.Transporter;
12
- config: any;
13
- }
14
-
15
- const sessions = new Map<string, SmtpSession>();
16
-
17
- // ─── 辅助 ───────────────────────────────────────────────────
18
-
19
- function getSession(sessionId: string): SmtpSession {
20
- const s = sessions.get(sessionId);
21
- if (!s) {
22
- throw new Error('SMTP not connected. Call smtpConnect first.');
23
- }
24
- return s;
25
- }
26
-
27
- // ─── 连接 ───────────────────────────────────────────────────
28
-
29
- export async function connect(config: any): Promise<any> {
30
- const sessionId = uuidv4();
31
-
32
- try {
33
- const transporter = nodemailer.createTransport({
34
- host: config.host,
35
- port: config.port ?? 465,
36
- secure: config.tls ?? true,
37
- auth: {
38
- user: config.username,
39
- pass: config.password,
40
- accessToken: config.accessToken,
41
- },
42
- authMethod: config.authType === 'oauth2' ? 'XOAUTH2' : undefined,
43
- tls: {
44
- rejectUnauthorized: config.checkCertificate ?? true,
45
- },
46
- name: config.helloName,
47
- connectionTimeout: config.timeout ?? 30000,
48
- greetingTimeout: config.timeout ?? 30000,
49
- socketTimeout: config.timeout ?? 30000,
50
- debug: config.debug ?? false,
51
- logger: config.debug ?? false,
52
- });
53
-
54
- sessions.set(sessionId, { transporter, config });
55
-
56
- // 获取服务器信息(verify 会连接并验证)
57
- let serverName = config.host;
58
- const capabilities: string[] = [];
59
- const supportedAuthMethods: string[] = [];
60
-
61
- try {
62
- await transporter.verify();
63
- } catch {
64
- // verify 失败不一定意味着连接失败,可能是认证问题
65
- // 我们仍然返回 session
66
- }
67
-
68
- return {
69
- success: true,
70
- sessionId,
71
- serverInfo: {
72
- serverName,
73
- capabilities,
74
- supportedAuthMethods,
75
- },
76
- };
77
- } catch (err: any) {
78
- return {
79
- success: false,
80
- error: err.message ?? 'SMTP connection failed',
81
- };
82
- }
83
- }
84
-
85
- // ─── 断开连接 ───────────────────────────────────────────────
86
-
87
- export async function disconnect(sessionId: string): Promise<void> {
88
- const s = sessions.get(sessionId);
89
- if (s) {
90
- s.transporter.close();
91
- sessions.delete(sessionId);
92
- }
93
- }
94
-
95
- // ─── 发送邮件 ──────────────────────────────────────────────
96
-
97
- export async function sendMail(sessionId: string, options: any): Promise<any> {
98
- const s = getSession(sessionId);
99
-
100
- try {
101
- // 转换附件格式
102
- const attachments: any[] = [];
103
- if (options.attachments) {
104
- for (const att of options.attachments) {
105
- const attachment: any = {
106
- filename: att.filename,
107
- contentType: att.mimeType,
108
- disposition:
109
- att.disposition ?? (att.isInline ? 'inline' : 'attachment'),
110
- };
111
-
112
- if (att.contentId) {
113
- attachment.contentId = att.contentId;
114
- attachment.cid = att.contentId;
115
- }
116
-
117
- // data 可能是 ArrayBuffer、Buffer 或 base64 字符串
118
- if (att.data) {
119
- if (typeof att.data === 'string') {
120
- // base64 编码的字符串
121
- attachment.content = Buffer.from(att.data, 'base64');
122
- attachment.encoding = 'base64';
123
- } else if (att.data instanceof ArrayBuffer) {
124
- attachment.content = Buffer.from(att.data);
125
- } else if (att.data.buffer instanceof ArrayBuffer) {
126
- attachment.content = Buffer.from(att.data.buffer);
127
- } else {
128
- attachment.content = att.data;
129
- }
130
- }
131
-
132
- attachments.push(attachment);
133
- }
134
- }
135
-
136
- // 构建邮件选项
137
- const mailOptions: any = {
138
- from: {
139
- name: options.from?.name ?? '',
140
- address: options.from?.email ?? '',
141
- },
142
- to: (options.to ?? []).map((a: any) => ({
143
- name: a.name ?? '',
144
- address: a.email ?? '',
145
- })),
146
- subject: options.subject ?? '',
147
- };
148
-
149
- if (options.cc && options.cc.length > 0) {
150
- mailOptions.cc = options.cc.map((a: any) => ({
151
- name: a.name ?? '',
152
- address: a.email ?? '',
153
- }));
154
- }
155
-
156
- if (options.bcc && options.bcc.length > 0) {
157
- mailOptions.bcc = options.bcc.map((a: any) => ({
158
- name: a.name ?? '',
159
- address: a.email ?? '',
160
- }));
161
- }
162
-
163
- if (options.replyTo && options.replyTo.length > 0) {
164
- mailOptions.replyTo = options.replyTo.map((a: any) => ({
165
- name: a.name ?? '',
166
- address: a.email ?? '',
167
- }));
168
- }
169
-
170
- if (options.textBody) mailOptions.text = options.textBody;
171
- if (options.htmlBody) mailOptions.html = options.htmlBody;
172
-
173
- if (attachments.length > 0) mailOptions.attachments = attachments;
174
-
175
- if (options.priority) {
176
- mailOptions.priority = options.priority;
177
- mailOptions.headers = mailOptions.headers ?? {};
178
- const priorityMap: Record<string, string> = {
179
- high: '1',
180
- normal: '3',
181
- low: '5',
182
- };
183
- mailOptions.headers['X-Priority'] = priorityMap[options.priority] ?? '3';
184
- }
185
-
186
- if (options.headers) {
187
- mailOptions.headers = {
188
- ...(mailOptions.headers ?? {}),
189
- ...options.headers,
190
- };
191
- }
192
-
193
- if (options.inReplyTo) mailOptions.inReplyTo = options.inReplyTo;
194
- if (options.references) mailOptions.references = options.references;
195
-
196
- if (options.readReceiptTo) {
197
- mailOptions.headers = mailOptions.headers ?? {};
198
- mailOptions.headers['Disposition-Notification-To'] =
199
- options.readReceiptTo.email;
200
- }
201
-
202
- if (options.charset) mailOptions.charset = options.charset;
203
- if (options.encoding) mailOptions.encoding = options.encoding;
204
-
205
- // 发送
206
- const info = await s.transporter.sendMail(mailOptions);
207
-
208
- return {
209
- success: true,
210
- messageId: info.messageId,
211
- date: new Date().toISOString(),
212
- serverResponseCode: info.response
213
- ? parseInt(info.response, 10) || 250
214
- : 250,
215
- queueId: info.messageId,
216
- };
217
- } catch (err: any) {
218
- return {
219
- success: false,
220
- error: err.message ?? 'Failed to send email',
221
- retryable: err.code === 'ECONNECTION' || err.code === 'ETIMEDOUT',
222
- };
223
- }
224
- }
225
-
226
- // ─── 验证连接 ──────────────────────────────────────────────
227
-
228
- export async function verifyConnection(sessionId: string): Promise<boolean> {
229
- const s = getSession(sessionId);
230
- try {
231
- await s.transporter.verify();
232
- return true;
233
- } catch {
234
- return false;
235
- }
236
- }
237
-
238
- // ─── 获取所有 session ID(用于清理)────────────────────────
239
-
240
- export function getAllSessionIds(): string[] {
241
- return Array.from(sessions.keys());
242
- }
1
+ // ============================================================
2
+ // SMTP 代理处理器 — 基于 nodemailer
3
+ // ============================================================
4
+
5
+ import nodemailer from 'nodemailer';
6
+ import { v4 as uuidv4 } from 'uuid';
7
+
8
+ // ─── 类型 ───────────────────────────────────────────────────
9
+
10
+ interface SmtpSession {
11
+ transporter: nodemailer.Transporter;
12
+ config: any;
13
+ /** 服务器 SIZE(RFC 1870)上限(字节),未通告为 0 */
14
+ maxMessageSize: number;
15
+ }
16
+
17
+ const sessions = new Map<string, SmtpSession>();
18
+
19
+ // ─── 辅助 ───────────────────────────────────────────────────
20
+
21
+ function getSession(sessionId: string): SmtpSession {
22
+ const s = sessions.get(sessionId);
23
+ if (!s) {
24
+ throw new Error('SMTP not connected. Call smtpConnect first.');
25
+ }
26
+ return s;
27
+ }
28
+
29
+ /** 轻量探测 SMTP 服务器 SIZE(RFC 1870)上限(字节);未通告返回 0。
30
+ * nodemailer 内部 SMTPConnection 做一次 EHLO 即读 `_maxAllowedSize` 后关闭。 */
31
+ async function probeMaxMessageSize(config: any): Promise<number> {
32
+ try {
33
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
34
+ const SMTPConnection: any = require('nodemailer/lib/smtp-connection');
35
+ const conn = new SMTPConnection({
36
+ host: config.host,
37
+ port: config.port ?? 465,
38
+ secure: config.tls ?? true,
39
+ connectionTimeout: config.timeout ?? 30000,
40
+ tls: { rejectUnauthorized: config.checkCertificate ?? true },
41
+ name: config.helloName,
42
+ logger: false,
43
+ });
44
+ return await new Promise<number>((resolve) => {
45
+ const done = (v: number) => {
46
+ try {
47
+ conn.close();
48
+ } catch {
49
+ /* ignore */
50
+ }
51
+ resolve(v);
52
+ };
53
+ conn.on('connect', () => done(conn._maxAllowedSize || 0));
54
+ conn.on('error', () => done(0));
55
+ conn.connect((err: any) => {
56
+ if (err) done(0);
57
+ });
58
+ });
59
+ } catch {
60
+ return 0;
61
+ }
62
+ }
63
+
64
+ // ─── 连接 ───────────────────────────────────────────────────
65
+
66
+ export async function connect(config: any): Promise<any> {
67
+ const sessionId = uuidv4();
68
+
69
+ try {
70
+ const transporter = nodemailer.createTransport({
71
+ host: config.host,
72
+ port: config.port ?? 465,
73
+ secure: config.tls ?? true,
74
+ auth: {
75
+ user: config.username,
76
+ pass: config.password,
77
+ accessToken: config.accessToken,
78
+ },
79
+ authMethod: config.authType === 'oauth2' ? 'XOAUTH2' : undefined,
80
+ tls: {
81
+ rejectUnauthorized: config.checkCertificate ?? true,
82
+ },
83
+ name: config.helloName,
84
+ connectionTimeout: config.timeout ?? 30000,
85
+ greetingTimeout: config.timeout ?? 30000,
86
+ socketTimeout: config.timeout ?? 30000,
87
+ debug: config.debug ?? false,
88
+ logger: config.debug ?? false,
89
+ });
90
+
91
+ sessions.set(sessionId, { transporter, config, maxMessageSize: 0 });
92
+
93
+ let serverName = config.host;
94
+ const capabilities: string[] = [];
95
+ const supportedAuthMethods: string[] = [];
96
+
97
+ // 探测服务器 SIZE(RFC 1870)上限,用于发信前预检。
98
+ // 说明:不再单独调 transporter.verify() —— nodemailer 非 pool 模式每次操作都新建连接、用完即关,
99
+ // 没有可复用的常驻连接;verify() 的失败此前也被忽略,属多余的一次握手,故合并到 probe 这一条连接里。
100
+ const maxMessageSize = await probeMaxMessageSize(config);
101
+ const session = sessions.get(sessionId);
102
+ if (session) session.maxMessageSize = maxMessageSize;
103
+ if (maxMessageSize > 0) {
104
+ capabilities.push(`SIZE=${maxMessageSize}`);
105
+ }
106
+
107
+ return {
108
+ success: true,
109
+ sessionId,
110
+ serverInfo: {
111
+ serverName,
112
+ capabilities,
113
+ supportedAuthMethods,
114
+ maxMessageSize,
115
+ },
116
+ };
117
+ } catch (err: any) {
118
+ return {
119
+ success: false,
120
+ error: err.message ?? 'SMTP connection failed',
121
+ };
122
+ }
123
+ }
124
+
125
+ // ─── 断开连接 ───────────────────────────────────────────────
126
+
127
+ export async function disconnect(sessionId: string): Promise<void> {
128
+ const s = sessions.get(sessionId);
129
+ if (s) {
130
+ s.transporter.close();
131
+ sessions.delete(sessionId);
132
+ }
133
+ }
134
+
135
+ // ─── 发送邮件 ──────────────────────────────────────────────
136
+
137
+ /** 估算邮件整体大小(字节),含 base64 膨胀与 MIME 边界开销 */
138
+ function estimateMailSize(mailOptions: any): number {
139
+ let size = 0;
140
+ if (mailOptions.text) size += Buffer.byteLength(String(mailOptions.text));
141
+ if (mailOptions.html) size += Buffer.byteLength(String(mailOptions.html));
142
+ for (const att of mailOptions.attachments ?? []) {
143
+ if (att.content && typeof att.content.length === 'number') {
144
+ // base64 膨胀 ≈ 4/3,留 1.4 余量;含 MIME 部分头
145
+ size += Math.ceil(att.content.length * 1.4) + 1024;
146
+ }
147
+ }
148
+ size += 4096; // 信封 + 头字段 + 边界开销
149
+ return Math.ceil(size);
150
+ }
151
+
152
+ export async function sendMail(sessionId: string, options: any): Promise<any> {
153
+ const s = getSession(sessionId);
154
+
155
+ try {
156
+ // 转换附件格式
157
+ const attachments: any[] = [];
158
+ if (options.attachments) {
159
+ for (const att of options.attachments) {
160
+ const attachment: any = {
161
+ filename: att.filename,
162
+ contentType: att.mimeType,
163
+ disposition:
164
+ att.disposition ?? (att.isInline ? 'inline' : 'attachment'),
165
+ };
166
+
167
+ if (att.contentId) {
168
+ attachment.contentId = att.contentId;
169
+ attachment.cid = att.contentId;
170
+ }
171
+
172
+ // data 可能是 ArrayBuffer、Buffer 或 base64 字符串
173
+ if (att.data) {
174
+ if (typeof att.data === 'string') {
175
+ // base64 编码的字符串
176
+ attachment.content = Buffer.from(att.data, 'base64');
177
+ attachment.encoding = 'base64';
178
+ } else if (att.data instanceof ArrayBuffer) {
179
+ attachment.content = Buffer.from(att.data);
180
+ } else if (att.data.buffer instanceof ArrayBuffer) {
181
+ attachment.content = Buffer.from(att.data.buffer);
182
+ } else {
183
+ attachment.content = att.data;
184
+ }
185
+ }
186
+
187
+ attachments.push(attachment);
188
+ }
189
+ }
190
+
191
+ // 构建邮件选项
192
+ const mailOptions: any = {
193
+ from: {
194
+ name: options.from?.name ?? '',
195
+ address: options.from?.email ?? '',
196
+ },
197
+ to: (options.to ?? []).map((a: any) => ({
198
+ name: a.name ?? '',
199
+ address: a.email ?? '',
200
+ })),
201
+ subject: options.subject ?? '',
202
+ };
203
+
204
+ if (options.cc && options.cc.length > 0) {
205
+ mailOptions.cc = options.cc.map((a: any) => ({
206
+ name: a.name ?? '',
207
+ address: a.email ?? '',
208
+ }));
209
+ }
210
+
211
+ if (options.bcc && options.bcc.length > 0) {
212
+ mailOptions.bcc = options.bcc.map((a: any) => ({
213
+ name: a.name ?? '',
214
+ address: a.email ?? '',
215
+ }));
216
+ }
217
+
218
+ if (options.replyTo && options.replyTo.length > 0) {
219
+ mailOptions.replyTo = options.replyTo.map((a: any) => ({
220
+ name: a.name ?? '',
221
+ address: a.email ?? '',
222
+ }));
223
+ }
224
+
225
+ if (options.textBody) mailOptions.text = options.textBody;
226
+ if (options.htmlBody) mailOptions.html = options.htmlBody;
227
+
228
+ if (attachments.length > 0) mailOptions.attachments = attachments;
229
+
230
+ if (options.priority) {
231
+ mailOptions.priority = options.priority;
232
+ mailOptions.headers = mailOptions.headers ?? {};
233
+ const priorityMap: Record<string, string> = {
234
+ high: '1',
235
+ normal: '3',
236
+ low: '5',
237
+ };
238
+ mailOptions.headers['X-Priority'] = priorityMap[options.priority] ?? '3';
239
+ }
240
+
241
+ if (options.headers) {
242
+ mailOptions.headers = {
243
+ ...(mailOptions.headers ?? {}),
244
+ ...options.headers,
245
+ };
246
+ }
247
+
248
+ if (options.inReplyTo) mailOptions.inReplyTo = options.inReplyTo;
249
+ if (options.references) mailOptions.references = options.references;
250
+
251
+ if (options.readReceiptTo) {
252
+ mailOptions.headers = mailOptions.headers ?? {};
253
+ mailOptions.headers['Disposition-Notification-To'] =
254
+ options.readReceiptTo.email;
255
+ }
256
+
257
+ if (options.charset) mailOptions.charset = options.charset;
258
+ if (options.encoding) mailOptions.encoding = options.encoding;
259
+
260
+ // 发信前预检:估算消息大小是否超过服务器 SIZE 限制(RFC 1870)
261
+ const maxSize = s.maxMessageSize ?? 0;
262
+ if (maxSize > 0) {
263
+ const estimated = estimateMailSize(mailOptions);
264
+ if (estimated > maxSize) {
265
+ return {
266
+ success: false,
267
+ error: `邮件大小约 ${Math.round(estimated / 1024)}KB 超过服务器 SIZE 限制 ${Math.round(maxSize / 1024)}KB(${maxSize} 字节)`,
268
+ retryable: false,
269
+ };
270
+ }
271
+ }
272
+
273
+ // 发送
274
+ const info = await s.transporter.sendMail(mailOptions);
275
+
276
+ return {
277
+ success: true,
278
+ messageId: info.messageId,
279
+ date: new Date().toISOString(),
280
+ serverResponseCode: info.response
281
+ ? parseInt(info.response, 10) || 250
282
+ : 250,
283
+ queueId: info.messageId,
284
+ };
285
+ } catch (err: any) {
286
+ return {
287
+ success: false,
288
+ error: err.message ?? 'Failed to send email',
289
+ retryable: err.code === 'ECONNECTION' || err.code === 'ETIMEDOUT',
290
+ };
291
+ }
292
+ }
293
+
294
+ // ─── 验证连接 ──────────────────────────────────────────────
295
+
296
+ export async function verifyConnection(sessionId: string): Promise<boolean> {
297
+ const s = getSession(sessionId);
298
+ try {
299
+ await s.transporter.verify();
300
+ return true;
301
+ } catch {
302
+ return false;
303
+ }
304
+ }
305
+
306
+ // ─── 获取所有 session ID(用于清理)────────────────────────
307
+
308
+ export function getAllSessionIds(): string[] {
309
+ return Array.from(sessions.keys());
310
+ }
@@ -45,6 +45,8 @@ export interface ConnectionConfig {
45
45
  checkCertificate: boolean;
46
46
  /** 是否输出调试日志 */
47
47
  debug: boolean;
48
+ /** 下载分块大小(字节),默认 1048576(1MB);调大可提升大附件下载速度 */
49
+ downloadChunkSize?: number;
48
50
  }
49
51
 
50
52
  /**
@@ -97,6 +99,8 @@ export interface SmtpServerInfo {
97
99
  capabilities: string[];
98
100
  /** 支持的认证方法列表 */
99
101
  supportedAuthMethods: string[];
102
+ /** 服务器接受的最大邮件大小(字节,RFC 1870 SIZE);未通告时为 undefined/0 */
103
+ maxMessageSize?: number;
100
104
  }
101
105
 
102
106
  /**
package/src/native.ts CHANGED
@@ -51,6 +51,7 @@ export async function imapConnect(
51
51
  timeout: config.timeout ?? 30000,
52
52
  checkCertificate: config.checkCertificate ?? true,
53
53
  debug: config.debug ?? false,
54
+ downloadChunkSize: config.downloadChunkSize,
54
55
  }) as Promise<IMAPConnectionResult>;
55
56
  }
56
57
 
package/src/types.ts CHANGED
@@ -51,6 +51,12 @@ export interface IMAPConfig {
51
51
  checkCertificate?: boolean;
52
52
  /** 是否在控制台输出调试日志 */
53
53
  debug?: boolean;
54
+ /**
55
+ * 下载分块大小(字节),默认 1048576(1MB)。
56
+ * Web 与 Android 通用:调大可减少大附件的分段请求次数、提升下载速度。
57
+ * 建议 256KB ~ 4MB;过大可能被服务器截断单次响应。
58
+ */
59
+ downloadChunkSize?: number;
54
60
  }
55
61
 
56
62
  /**
@@ -115,6 +121,8 @@ export interface SMTPConnectionResult {
115
121
  capabilities: string[];
116
122
  /** 服务器支持的认证方法,如 `PLAIN`、`LOGIN`、`XOAUTH2` */
117
123
  supportedAuthMethods: string[];
124
+ /** 服务器接受的最大邮件大小(字节,RFC 1870 SIZE);未通告时为 0 或不返回 */
125
+ maxMessageSize?: number;
118
126
  };
119
127
  /** 连接失败时的错误信息(成功时为空) */
120
128
  error?: string;