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.
- package/README.md +1 -1
- package/android/src/main/java/com/margelo/nitro/emailimapsmtp/EmailImapSmtp.kt +199 -114
- package/lib/module/native.js +2 -1
- package/lib/module/native.js.map +1 -1
- package/lib/typescript/server/src/imapHandler.d.ts +5 -0
- package/lib/typescript/server/src/imapHandler.d.ts.map +1 -1
- package/lib/typescript/server/src/index.d.ts.map +1 -1
- package/lib/typescript/server/src/smtpHandler.d.ts.map +1 -1
- package/lib/typescript/src/EmailImapSmtp.nitro.d.ts +4 -0
- package/lib/typescript/src/EmailImapSmtp.nitro.d.ts.map +1 -1
- package/lib/typescript/src/native.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +8 -0
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JConnectionConfig.hpp +7 -3
- package/nitrogen/generated/android/c++/JSmtpServerInfo.hpp +8 -3
- package/nitrogen/generated/android/c++/JVariant_ImapServerInfo_SmtpServerInfo.hpp +1 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/emailimapsmtp/ConnectionConfig.kt +9 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/emailimapsmtp/SmtpServerInfo.kt +9 -4
- package/nitrogen/generated/ios/EmailImapSmtp-Swift-Cxx-Bridge.hpp +15 -15
- package/nitrogen/generated/ios/swift/ConnectionConfig.swift +20 -2
- package/nitrogen/generated/ios/swift/SmtpServerInfo.swift +19 -1
- package/nitrogen/generated/shared/c++/ConnectionConfig.hpp +6 -2
- package/nitrogen/generated/shared/c++/SmtpServerInfo.hpp +7 -2
- package/package.json +1 -1
- package/server/lib/imapHandler.d.ts +5 -0
- package/server/lib/imapHandler.d.ts.map +1 -1
- package/server/lib/imapHandler.js +247 -77
- package/server/lib/imapHandler.js.map +1 -1
- package/server/lib/index.d.ts.map +1 -1
- package/server/lib/index.js +24 -9
- package/server/lib/index.js.map +1 -1
- package/server/lib/smtpHandler.d.ts.map +1 -1
- package/server/lib/smtpHandler.js +76 -8
- package/server/lib/smtpHandler.js.map +1 -1
- package/server/package-lock.json +1 -0
- package/server/package.json +1 -0
- package/server/src/imapHandler.ts +273 -76
- package/server/src/imapflow.d.ts +31 -0
- package/server/src/index.ts +50 -16
- package/server/src/smtpHandler.ts +310 -242
- package/src/EmailImapSmtp.nitro.ts +4 -0
- package/src/native.ts +1 -0
- package/src/types.ts +8 -0
package/README.md
CHANGED
|
@@ -46,6 +46,8 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
46
46
|
private var smtpTransport: SMTPTransport? = null
|
|
47
47
|
private var smtpSessionCache: Session? = null
|
|
48
48
|
private var smtpConfig: SmtpConnectionConfig? = null
|
|
49
|
+
/** 服务器 SIZE(RFC 1870)上限(字节),用于发信前预检;未通告为 null */
|
|
50
|
+
private var smtpMaxMessageSize: Double? = null
|
|
49
51
|
private var selectedMailbox: String? = null
|
|
50
52
|
private var imapConfig: ConnectionConfig? = null
|
|
51
53
|
|
|
@@ -73,7 +75,8 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
73
75
|
put("mail.imap.timeout", config.timeout.toInt().toString())
|
|
74
76
|
put("mail.imap.writetimeout", config.timeout.toInt().toString())
|
|
75
77
|
put("mail.store.protocol", "imap")
|
|
76
|
-
|
|
78
|
+
// 下载分块大小:默认 1MB,可由 config.downloadChunkSize 覆盖(与 Web 端对齐)
|
|
79
|
+
put("mail.imap.fetchsize", (config.downloadChunkSize?.toInt() ?: 1048576).toString())
|
|
77
80
|
put("mail.imap.partialfetch", "true")
|
|
78
81
|
// 增加连接保活相关设置
|
|
79
82
|
// 注意: 不设置 separatestoreconnection,让 store 和 folder 共用同一连接
|
|
@@ -142,7 +145,9 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
142
145
|
return imapStore ?: throw Exception("Not connected to IMAP server.")
|
|
143
146
|
}
|
|
144
147
|
|
|
145
|
-
/** 确保 IMAP Store
|
|
148
|
+
/** 确保 IMAP Store 连接存活,若已断开则自动使用保存的配置重连。
|
|
149
|
+
* @Synchronized:多个并发请求同时发现断开时串行重连,避免重连风暴。 */
|
|
150
|
+
@Synchronized
|
|
146
151
|
private fun ensureStoreConnected(): IMAPStore {
|
|
147
152
|
val store = ensureImapStore()
|
|
148
153
|
if (!store.isConnected()) {
|
|
@@ -166,6 +171,27 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
166
171
|
return store
|
|
167
172
|
}
|
|
168
173
|
|
|
174
|
+
/**
|
|
175
|
+
* 读操作统一包装:捕获 FolderClosedException 或「连接已断」的 MessagingException 时,
|
|
176
|
+
* 内部 attempt 会再次调用 ensureStoreConnected/ensureFolderOpen 自动重连,然后重试一次。
|
|
177
|
+
* 仅用于读操作;写操作不自动重试(避免断线重试造成重复执行)。
|
|
178
|
+
* inline:允许 attempt 内使用非局部 return@async。
|
|
179
|
+
*/
|
|
180
|
+
private inline fun <T> withImapRetry(attempt: () -> T): T {
|
|
181
|
+
try {
|
|
182
|
+
return attempt()
|
|
183
|
+
} catch (e: jakarta.mail.FolderClosedException) {
|
|
184
|
+
Log.w(TAG, "FolderClosedException, auto-reconnect & retry: ${e.message}")
|
|
185
|
+
return attempt()
|
|
186
|
+
} catch (e: jakarta.mail.MessagingException) {
|
|
187
|
+
if (imapStore?.isConnected != true) {
|
|
188
|
+
Log.w(TAG, "IMAP connection lost, auto-reconnect & retry: ${e.message}")
|
|
189
|
+
return attempt()
|
|
190
|
+
}
|
|
191
|
+
throw e
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
169
195
|
// ─── 保活(Keep-Alive)────────────────────────────────────
|
|
170
196
|
// 定期发送 NOOP 命令防止 IMAP 服务器因空闲超时断开连接
|
|
171
197
|
|
|
@@ -242,7 +268,8 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
242
268
|
onText = { bodyText = it },
|
|
243
269
|
onHtml = { bodyHtml = it },
|
|
244
270
|
onEmbedded = { embeddedAttachments.add(it) },
|
|
245
|
-
onAttachment = { attachments.add(it) }
|
|
271
|
+
onAttachment = { attachments.add(it) },
|
|
272
|
+
fullData = false)
|
|
246
273
|
} catch (_: Exception) {
|
|
247
274
|
bodyText = mime.content?.toString() ?: ""
|
|
248
275
|
}
|
|
@@ -277,6 +304,27 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
277
304
|
)
|
|
278
305
|
}
|
|
279
306
|
|
|
307
|
+
/** 只读附件元数据(不下载内容),用于列表阶段避免拉取全部附件。
|
|
308
|
+
* 与 readAttachmentData 字段一致,但 data 为空、localPath 为 null。 */
|
|
309
|
+
private fun readAttachmentMeta(
|
|
310
|
+
part: BodyPart, fileName: String, contentId: String?,
|
|
311
|
+
isInline: Boolean, disp: String
|
|
312
|
+
): AttachmentInfo {
|
|
313
|
+
val sz = part.size
|
|
314
|
+
return AttachmentInfo(
|
|
315
|
+
filename = fileName,
|
|
316
|
+
mimeType = part.contentType ?: "application/octet-stream",
|
|
317
|
+
partId = contentId ?: fileName,
|
|
318
|
+
size = if (sz > 0) sz.toDouble() else 0.0,
|
|
319
|
+
data = ArrayBuffer.copy(ByteArray(0)),
|
|
320
|
+
contentId = contentId,
|
|
321
|
+
isInline = isInline,
|
|
322
|
+
charset = part.contentType?.let { extractCharsetFromMimeType(it) },
|
|
323
|
+
contentDisposition = disp,
|
|
324
|
+
localPath = null
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
|
|
280
328
|
/**
|
|
281
329
|
* 与 Web 端(imapflow bodyStructure walk)对齐的附件叶子判定:
|
|
282
330
|
* disposition=attachment / 有 filename / 非 text 类型 → 视为附件。
|
|
@@ -286,6 +334,7 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
286
334
|
part: Part,
|
|
287
335
|
onEmbedded: (String) -> Unit,
|
|
288
336
|
onAttachment: (AttachmentInfo) -> Unit,
|
|
337
|
+
fullData: Boolean = true,
|
|
289
338
|
) {
|
|
290
339
|
val disp = part.disposition ?: ""
|
|
291
340
|
val isAttachment = disp.equals(Part.ATTACHMENT, ignoreCase = true)
|
|
@@ -296,7 +345,10 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
296
345
|
val primary = part.contentType?.substringBefore('/')?.trim()?.lowercase() ?: ""
|
|
297
346
|
val isNonText = primary.isNotEmpty() && primary != "text" && primary != "multipart"
|
|
298
347
|
if (isAttachment || isInline || contentId != null || isNonText) {
|
|
299
|
-
|
|
348
|
+
// fullData=false(列表阶段):只取元数据,不读附件内容,避免列表下载全部附件
|
|
349
|
+
val info =
|
|
350
|
+
if (fullData) readAttachmentData(part as BodyPart, fileName, contentId, isInline, disp)
|
|
351
|
+
else readAttachmentMeta(part, fileName, contentId, isInline, disp)
|
|
300
352
|
if (isInline && contentId != null) {
|
|
301
353
|
onEmbedded(fileName)
|
|
302
354
|
}
|
|
@@ -322,18 +374,19 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
322
374
|
onHtml: (String) -> Unit,
|
|
323
375
|
onEmbedded: (String) -> Unit,
|
|
324
376
|
onAttachment: (AttachmentInfo) -> Unit,
|
|
377
|
+
fullData: Boolean = true,
|
|
325
378
|
) {
|
|
326
379
|
if (part.isMimeType("text/plain")) {
|
|
327
380
|
// text/plain 也可能是附件(带 attachment disposition / filename / name):
|
|
328
381
|
// 先判定附件,再当作正文。与 Web 端一致(1.txt/2.txt 等 text/plain 附件)。
|
|
329
382
|
if (isAttachmentLike(part)) {
|
|
330
|
-
handleAttachmentLeaf(part, onEmbedded, onAttachment)
|
|
383
|
+
handleAttachmentLeaf(part, onEmbedded, onAttachment, fullData)
|
|
331
384
|
} else {
|
|
332
385
|
onText(part.content?.toString() ?: "")
|
|
333
386
|
}
|
|
334
387
|
} else if (part.isMimeType("text/html")) {
|
|
335
388
|
if (isAttachmentLike(part)) {
|
|
336
|
-
handleAttachmentLeaf(part, onEmbedded, onAttachment)
|
|
389
|
+
handleAttachmentLeaf(part, onEmbedded, onAttachment, fullData)
|
|
337
390
|
} else {
|
|
338
391
|
onHtml(part.content?.toString() ?: "")
|
|
339
392
|
}
|
|
@@ -349,19 +402,19 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
349
402
|
onText(bp.content?.toString() ?: ""); foundText = true
|
|
350
403
|
} else if (bp.isMimeType("multipart/*")) {
|
|
351
404
|
// alternative 内嵌套的子 multipart(related/mixed 等)→ 递归,不遗漏附件
|
|
352
|
-
parseBodyParts(bp, onText, onHtml, onEmbedded, onAttachment)
|
|
405
|
+
parseBodyParts(bp, onText, onHtml, onEmbedded, onAttachment, fullData)
|
|
353
406
|
} else {
|
|
354
407
|
// alternative 内的非正文叶子(内嵌图/附件)→ 附件判定
|
|
355
|
-
handleAttachmentLeaf(bp, onEmbedded, onAttachment)
|
|
408
|
+
handleAttachmentLeaf(bp, onEmbedded, onAttachment, fullData)
|
|
356
409
|
}
|
|
357
410
|
}
|
|
358
411
|
} else if (part.isMimeType("multipart/*")) {
|
|
359
412
|
val mp = part.content as? Multipart ?: return
|
|
360
413
|
for (i in 0 until mp.count) {
|
|
361
|
-
parseBodyParts(mp.getBodyPart(i), onText, onHtml, onEmbedded, onAttachment)
|
|
414
|
+
parseBodyParts(mp.getBodyPart(i), onText, onHtml, onEmbedded, onAttachment, fullData)
|
|
362
415
|
}
|
|
363
416
|
} else {
|
|
364
|
-
handleAttachmentLeaf(part, onEmbedded, onAttachment)
|
|
417
|
+
handleAttachmentLeaf(part, onEmbedded, onAttachment, fullData)
|
|
365
418
|
}
|
|
366
419
|
}
|
|
367
420
|
|
|
@@ -578,17 +631,19 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
578
631
|
|
|
579
632
|
override fun imapListMailboxes(): Promise<Array<MailboxListItem>> {
|
|
580
633
|
return Promise.async {
|
|
581
|
-
val store = ensureStoreConnected()
|
|
582
634
|
val result = mutableListOf<MailboxListItem>()
|
|
583
635
|
try {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
636
|
+
withImapRetry {
|
|
637
|
+
val store = ensureStoreConnected()
|
|
638
|
+
store.defaultFolder.list("*").forEach { f ->
|
|
639
|
+
result.add(
|
|
640
|
+
MailboxListItem(
|
|
641
|
+
name = f.name ?: "", path = f.fullName ?: "",
|
|
642
|
+
delimiter = f.separator.toString(), flags = emptyArray(),
|
|
643
|
+
subscribed = f.isSubscribed
|
|
644
|
+
)
|
|
590
645
|
)
|
|
591
|
-
|
|
646
|
+
}
|
|
592
647
|
}
|
|
593
648
|
} catch (e: Exception) {
|
|
594
649
|
Log.e(TAG, "List mailboxes failed", e)
|
|
@@ -655,21 +710,23 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
655
710
|
|
|
656
711
|
override fun imapRefreshMailbox(): Promise<MailboxInfo> {
|
|
657
712
|
return Promise.async {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
val
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
713
|
+
withImapRetry {
|
|
714
|
+
val f = ensureFolderOpen()
|
|
715
|
+
val firstUnseenUid = try {
|
|
716
|
+
val unseen = f.search(FlagTerm(Flags().apply { add(Flags.Flag.SEEN) }, false))
|
|
717
|
+
if (unseen.isNotEmpty()) f.getUID(unseen[0]).toDouble() else 0.0
|
|
718
|
+
} catch (_: Exception) { 0.0 }
|
|
719
|
+
return@async MailboxInfo(
|
|
720
|
+
name = f.name ?: "", path = f.fullName ?: "",
|
|
721
|
+
uidNext = f.uidNext.toDouble(),
|
|
722
|
+
uidValidity = f.uidValidity.toDouble(),
|
|
723
|
+
messageCount = f.messageCount.toDouble(),
|
|
724
|
+
recentCount = f.newMessageCount.toDouble(),
|
|
725
|
+
unseenCount = f.unreadMessageCount.toDouble(),
|
|
726
|
+
firstUnseenUid = firstUnseenUid, highestModSeq = 0.0,
|
|
727
|
+
flags = emptyArray(), permanentFlags = emptyArray()
|
|
728
|
+
)
|
|
729
|
+
}
|
|
673
730
|
}
|
|
674
731
|
}
|
|
675
732
|
|
|
@@ -677,20 +734,22 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
677
734
|
|
|
678
735
|
override fun imapFetchFolders(): Promise<Array<FolderInfo>> {
|
|
679
736
|
return Promise.async {
|
|
680
|
-
val store = ensureStoreConnected()
|
|
681
737
|
val result = mutableListOf<FolderInfo>()
|
|
682
738
|
try {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
739
|
+
withImapRetry {
|
|
740
|
+
val store = ensureStoreConnected()
|
|
741
|
+
store.defaultFolder.list("*").forEach { f ->
|
|
742
|
+
result.add(
|
|
743
|
+
FolderInfo(
|
|
744
|
+
name = f.name ?: "", path = f.fullName ?: "",
|
|
745
|
+
delimiter = f.separator.toString(),
|
|
746
|
+
parent = f.parent?.fullName ?: "",
|
|
747
|
+
children = emptyArray(), flags = emptyArray(),
|
|
748
|
+
subscribed = f.isSubscribed,
|
|
749
|
+
messageCount = 0.0, unseenCount = 0.0
|
|
750
|
+
)
|
|
692
751
|
)
|
|
693
|
-
|
|
752
|
+
}
|
|
694
753
|
}
|
|
695
754
|
} catch (e: Exception) {
|
|
696
755
|
Log.e(TAG, "Fetch folders failed", e)
|
|
@@ -849,10 +908,12 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
849
908
|
override fun imapFetchEmailByUID(uid: Double): Promise<Variant_NullType_EmailMessage> {
|
|
850
909
|
return Promise.async {
|
|
851
910
|
try {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
911
|
+
withImapRetry {
|
|
912
|
+
val folder = ensureFolderOpen()
|
|
913
|
+
val msg = folder.getMessageByUID(uid.toLong())
|
|
914
|
+
if (msg != null) {
|
|
915
|
+
return@async Variant_NullType_EmailMessage.create(emailToEmailMessage(msg, folder))
|
|
916
|
+
}
|
|
856
917
|
}
|
|
857
918
|
} catch (e: Exception) {
|
|
858
919
|
Log.e(TAG, "Fetch by UID failed", e)
|
|
@@ -868,7 +929,9 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
868
929
|
val result = mutableListOf<EmailMessage>()
|
|
869
930
|
|
|
870
931
|
try {
|
|
871
|
-
|
|
932
|
+
withImapRetry {
|
|
933
|
+
result.clear() // 重试前清空,避免断线重试时重复累积
|
|
934
|
+
// ── 若指定了 mailbox,先切换到该邮箱(略过已选中的)─
|
|
872
935
|
if (criteria.mailbox != null && criteria.mailbox != selectedMailbox) {
|
|
873
936
|
val store = ensureStoreConnected()
|
|
874
937
|
val raw = store.getFolder(criteria.mailbox) ?: throw Exception("Mailbox not found: ${criteria.mailbox}")
|
|
@@ -961,6 +1024,7 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
961
1024
|
for (i in 0 until limit) {
|
|
962
1025
|
result.add(emailToEmailMessage(sortedMsgs[i], folder))
|
|
963
1026
|
}
|
|
1027
|
+
}
|
|
964
1028
|
} catch (e: Exception) {
|
|
965
1029
|
Log.e(TAG, "Search failed", e)
|
|
966
1030
|
}
|
|
@@ -973,31 +1037,31 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
973
1037
|
override fun imapMarkAsRead(uids: DoubleArray, silent: Boolean): Promise<Unit> {
|
|
974
1038
|
return Promise.async {
|
|
975
1039
|
val folder = ensureFolderOpen()
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
// silent: 仅设置 flags,不触发 FolderListener 事件
|
|
980
|
-
// 非 silent: 设置 flags 并等待服务器确认
|
|
981
|
-
msg.setFlag(Flags.Flag.SEEN, true)
|
|
982
|
-
if (!silent) {
|
|
983
|
-
// 非 silent 模式下强制同步到服务器
|
|
984
|
-
folder.fetch(arrayOf(msg), FetchProfile().apply { add(FetchProfile.Item.FLAGS) })
|
|
985
|
-
}
|
|
986
|
-
} catch (_: Exception) {}
|
|
1040
|
+
// 批量:解析目标邮件(本地代理,不触发网络)后一次 STORE 设置 SEEN
|
|
1041
|
+
val msgs = uids.mapNotNull { uid ->
|
|
1042
|
+
try { folder.getMessageByUID(uid.toLong()) } catch (_: Exception) { null }
|
|
987
1043
|
}
|
|
1044
|
+
if (msgs.isEmpty()) return@async
|
|
1045
|
+
try {
|
|
1046
|
+
folder.setFlags(msgs.toTypedArray(), Flags(Flags.Flag.SEEN), true)
|
|
1047
|
+
if (!silent) {
|
|
1048
|
+
// 非 silent 模式下强制同步到服务器(确认 flags 已写入)
|
|
1049
|
+
folder.fetch(msgs.toTypedArray(), FetchProfile().apply { add(FetchProfile.Item.FLAGS) })
|
|
1050
|
+
}
|
|
1051
|
+
} catch (_: Exception) {}
|
|
988
1052
|
}
|
|
989
1053
|
}
|
|
990
1054
|
|
|
991
1055
|
override fun imapMarkAsFlagged(uids: DoubleArray, flagged: Boolean): Promise<Unit> {
|
|
992
1056
|
return Promise.async {
|
|
993
1057
|
val folder = ensureFolderOpen()
|
|
994
|
-
uids.
|
|
995
|
-
try {
|
|
996
|
-
val msg = folder.getMessageByUID(uid.toLong()) ?: return@forEach
|
|
997
|
-
if (flagged) msg.setFlags(Flags(Flags.Flag.FLAGGED), true)
|
|
998
|
-
else msg.setFlags(Flags(Flags.Flag.FLAGGED), false)
|
|
999
|
-
} catch (_: Exception) {}
|
|
1058
|
+
val msgs = uids.mapNotNull { uid ->
|
|
1059
|
+
try { folder.getMessageByUID(uid.toLong()) } catch (_: Exception) { null }
|
|
1000
1060
|
}
|
|
1061
|
+
if (msgs.isEmpty()) return@async
|
|
1062
|
+
try {
|
|
1063
|
+
folder.setFlags(msgs.toTypedArray(), Flags(Flags.Flag.FLAGGED), flagged)
|
|
1064
|
+
} catch (_: Exception) {}
|
|
1001
1065
|
}
|
|
1002
1066
|
}
|
|
1003
1067
|
|
|
@@ -1025,9 +1089,9 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
1025
1089
|
// 先复制到目标文件夹
|
|
1026
1090
|
folder.copyMessages(msgs, dest)
|
|
1027
1091
|
lastError = null
|
|
1028
|
-
//
|
|
1092
|
+
// 复制成功后,在原文件夹批量标记删除并 expunge
|
|
1029
1093
|
try {
|
|
1030
|
-
|
|
1094
|
+
folder.setFlags(msgs, Flags(Flags.Flag.DELETED), true)
|
|
1031
1095
|
ensureFolderOpen().expunge()
|
|
1032
1096
|
} catch (e: Exception) {
|
|
1033
1097
|
Log.e(TAG, "Move: expunge after copy failed: ${e.message}")
|
|
@@ -1082,44 +1146,32 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
1082
1146
|
return Promise.async {
|
|
1083
1147
|
val success = mutableListOf<Double>()
|
|
1084
1148
|
val failed = mutableListOf<Double>()
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
Log.d(TAG, "Deleted UID=$uid")
|
|
1095
|
-
} else {
|
|
1096
|
-
Log.w(TAG, "Delete failed: message UID=$uid not found (already deleted?)")
|
|
1097
|
-
failed.add(uid)
|
|
1098
|
-
}
|
|
1099
|
-
break
|
|
1100
|
-
} catch (e: FolderClosedException) {
|
|
1101
|
-
if (!retried) {
|
|
1102
|
-
Log.w(TAG, "Folder closed during delete UID=$uid, re-opening and retrying...")
|
|
1103
|
-
retried = true
|
|
1104
|
-
continue
|
|
1105
|
-
}
|
|
1106
|
-
Log.e(TAG, "Delete failed for UID=$uid after retry: ${e.message}")
|
|
1107
|
-
failed.add(uid)
|
|
1108
|
-
break
|
|
1109
|
-
} catch (e: Exception) {
|
|
1110
|
-
Log.e(TAG, "Delete failed for UID=$uid: ${e.message}")
|
|
1149
|
+
val folder = ensureFolderOpen()
|
|
1150
|
+
// 解析目标邮件(本地代理,不触发网络往返)
|
|
1151
|
+
val resolved = mutableListOf<Pair<Double, Message>>()
|
|
1152
|
+
for (uid in uids) {
|
|
1153
|
+
try {
|
|
1154
|
+
val msg = folder.getMessageByUID(uid.toLong())
|
|
1155
|
+
if (msg != null) resolved.add(uid to msg)
|
|
1156
|
+
else {
|
|
1157
|
+
Log.w(TAG, "Delete failed: message UID=$uid not found (already deleted?)")
|
|
1111
1158
|
failed.add(uid)
|
|
1112
|
-
break
|
|
1113
1159
|
}
|
|
1160
|
+
} catch (e: Exception) {
|
|
1161
|
+
Log.e(TAG, "Delete failed for UID=$uid: ${e.message}")
|
|
1162
|
+
failed.add(uid)
|
|
1114
1163
|
}
|
|
1115
1164
|
}
|
|
1116
|
-
//
|
|
1117
|
-
if (
|
|
1165
|
+
// 批量标记 DELETED 并一次性 EXPUNGE(一次命令完成,不再逐封往返)
|
|
1166
|
+
if (resolved.isNotEmpty()) {
|
|
1118
1167
|
try {
|
|
1168
|
+
folder.setFlags(resolved.map { it.second }.toTypedArray(), Flags(Flags.Flag.DELETED), true)
|
|
1119
1169
|
ensureFolderOpen().expunge()
|
|
1170
|
+
resolved.forEach { success.add(it.first) }
|
|
1120
1171
|
Log.d(TAG, "Expunge completed after deleting ${success.size} messages")
|
|
1121
1172
|
} catch (e: Exception) {
|
|
1122
|
-
Log.e(TAG, "
|
|
1173
|
+
Log.e(TAG, "Batch delete failed: ${e.message}")
|
|
1174
|
+
resolved.forEach { failed.add(it.first) }
|
|
1123
1175
|
}
|
|
1124
1176
|
}
|
|
1125
1177
|
DeleteResult(
|
|
@@ -1143,11 +1195,13 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
1143
1195
|
override fun imapFetchAttachments(uid: Double, partId: String): Promise<Variant_NullType_AttachmentInfo> {
|
|
1144
1196
|
return Promise.async {
|
|
1145
1197
|
try {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1198
|
+
withImapRetry {
|
|
1199
|
+
val folder = ensureFolderOpen()
|
|
1200
|
+
val msg = folder.getMessageByUID(uid.toLong()) ?: return@async Variant_NullType_AttachmentInfo.create(com.margelo.nitro.core.NullType.NULL)
|
|
1201
|
+
val result = findAttachmentByPartId(msg, partId)
|
|
1202
|
+
if (result != null) {
|
|
1203
|
+
return@async Variant_NullType_AttachmentInfo.create(result)
|
|
1204
|
+
}
|
|
1151
1205
|
}
|
|
1152
1206
|
} catch (e: Exception) {
|
|
1153
1207
|
Log.e(TAG, "Fetch attachment failed", e)
|
|
@@ -1269,15 +1323,17 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
1269
1323
|
override fun imapGetQuota(root: String?): Promise<QuotaInfo> {
|
|
1270
1324
|
return Promise.async {
|
|
1271
1325
|
try {
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1326
|
+
withImapRetry {
|
|
1327
|
+
val quotas = ensureStoreConnected().getQuota(root ?: "")
|
|
1328
|
+
val r = quotas.firstOrNull()?.resources?.firstOrNull()
|
|
1329
|
+
return@async QuotaInfo(
|
|
1330
|
+
storageUsed = r?.usage?.toDouble() ?: 0.0,
|
|
1331
|
+
storageLimit = r?.limit?.toDouble() ?: -1.0,
|
|
1332
|
+
storageUnit = "KB",
|
|
1333
|
+
messagesUsed = null, messagesLimit = null,
|
|
1334
|
+
root = root ?: ""
|
|
1335
|
+
)
|
|
1336
|
+
}
|
|
1281
1337
|
} catch (_: Exception) {
|
|
1282
1338
|
QuotaInfo(storageUsed = 0.0, storageLimit = -1.0, storageUnit = "KB",
|
|
1283
1339
|
messagesUsed = null, messagesLimit = null, root = root ?: "")
|
|
@@ -1415,13 +1471,20 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
1415
1471
|
smtpTransport = transport
|
|
1416
1472
|
smtpSessionCache = session
|
|
1417
1473
|
smtpConfig = config
|
|
1474
|
+
// 读取服务器 SIZE(RFC 1870)上限,供发信前判断数据大小是否合适
|
|
1475
|
+
val sizeParam = try { transport.getExtensionParameter("SIZE") } catch (_: Exception) { null }
|
|
1476
|
+
val maxMessageSize = sizeParam?.trim()?.toLongOrNull()?.takeIf { it > 0 }?.toDouble()
|
|
1477
|
+
smtpMaxMessageSize = maxMessageSize
|
|
1478
|
+
val caps = mutableListOf<String>()
|
|
1479
|
+
if (maxMessageSize != null) caps.add("SIZE=${maxMessageSize.toLong()}")
|
|
1418
1480
|
ConnectionResult(
|
|
1419
1481
|
success = true,
|
|
1420
1482
|
serverInfo = Variant_ImapServerInfo_SmtpServerInfo.create(
|
|
1421
1483
|
SmtpServerInfo(
|
|
1422
1484
|
serverName = config.host,
|
|
1423
|
-
capabilities =
|
|
1424
|
-
supportedAuthMethods = arrayOf("LOGIN", "PLAIN")
|
|
1485
|
+
capabilities = caps.toTypedArray(),
|
|
1486
|
+
supportedAuthMethods = arrayOf("LOGIN", "PLAIN"),
|
|
1487
|
+
maxMessageSize = maxMessageSize
|
|
1425
1488
|
)
|
|
1426
1489
|
),
|
|
1427
1490
|
error = null
|
|
@@ -1439,6 +1502,7 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
1439
1502
|
smtpTransport = null
|
|
1440
1503
|
smtpSessionCache = null
|
|
1441
1504
|
smtpConfig = null
|
|
1505
|
+
smtpMaxMessageSize = null
|
|
1442
1506
|
}
|
|
1443
1507
|
}
|
|
1444
1508
|
|
|
@@ -1455,6 +1519,27 @@ class EmailImapSmtp : HybridEmailImapSmtpSpec() {
|
|
|
1455
1519
|
error = "SMTP not configured. Call smtpConnect first.", retryable = true
|
|
1456
1520
|
)
|
|
1457
1521
|
|
|
1522
|
+
// 发信前预检:估算消息大小是否超过服务器 SIZE 限制(RFC 1870)
|
|
1523
|
+
val maxSize = smtpMaxMessageSize
|
|
1524
|
+
if (maxSize != null && maxSize > 0) {
|
|
1525
|
+
var estimated = 0L
|
|
1526
|
+
if (options.textBody != null) estimated += options.textBody.toByteArray(Charsets.UTF_8).size
|
|
1527
|
+
if (options.htmlBody != null) estimated += options.htmlBody.toByteArray(Charsets.UTF_8).size
|
|
1528
|
+
preCopiedAttachments?.forEach { attBytes ->
|
|
1529
|
+
// base64 膨胀 ≈ 4/3,留 1.4 余量 + MIME 部分头
|
|
1530
|
+
estimated += (attBytes.size * 1.4).toLong() + 1024
|
|
1531
|
+
}
|
|
1532
|
+
estimated += 4096 // 信封 + 头字段 + 边界
|
|
1533
|
+
if (estimated > maxSize.toLong()) {
|
|
1534
|
+
return@async SendMailResult(
|
|
1535
|
+
success = false, messageId = null, date = null,
|
|
1536
|
+
serverResponseCode = null, rawMimeData = null, queueId = null,
|
|
1537
|
+
error = "邮件大小约 ${estimated / 1024}KB 超过服务器 SIZE 限制 ${maxSize.toLong() / 1024}KB(${maxSize.toLong()} 字节)",
|
|
1538
|
+
retryable = false
|
|
1539
|
+
)
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1458
1543
|
// 即用即连:每次发送创建临时连接,避免长连接失效
|
|
1459
1544
|
var tempTransport: SMTPTransport? = null
|
|
1460
1545
|
try {
|
package/lib/module/native.js
CHANGED
|
@@ -27,7 +27,8 @@ export async function imapConnect(config) {
|
|
|
27
27
|
accessToken: config.accessToken,
|
|
28
28
|
timeout: config.timeout ?? 30000,
|
|
29
29
|
checkCertificate: config.checkCertificate ?? true,
|
|
30
|
-
debug: config.debug ?? false
|
|
30
|
+
debug: config.debug ?? false,
|
|
31
|
+
downloadChunkSize: config.downloadChunkSize
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
34
|
export async function imapDisconnect() {
|
package/lib/module/native.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NitroModules","hybridObject","getHybridObject","createHybridObject","imapConnect","config","h","host","port","username","password","tls","authType","accessToken","timeout","checkCertificate","debug","imapDisconnect","imapListMailboxes","imapSelectMailbox","mailbox","readOnly","imapRefreshMailbox","imapFetchFolders","imapCreateFolder","folderName","imapDeleteFolder","imapRenameFolder","oldName","newName","imapSubscribeFolder","imapUnsubscribeFolder","imapFetchEmails","options","from","to","rangeType","page","pageSize","since","before","fetchBody","fetchAttachments","fetchFlags","fetchHeaders","fetchFullContent","maxBodySize","imapFetchEmailByUID","uid","imapSearchEmails","criteria","text","subject","body","on","sentSince","sentBefore","flagged","seen","answered","draft","deleted","junk","hasAttachment","uids","header","larger","smaller","sortOrder","limit","imapMarkAsRead","silent","imapMarkAsFlagged","imapMoveEmails","destinationMailbox","imapCopyEmails","imapDeleteEmails","imapExpunge","imapFetchAttachments","partId","imapFetchAllAttachments","imapIdle","callback","imapStopIdle","imapGetQuota","root","imapAppendMessage","rawMimeData","flags","smtpConnect","helloName","smtpDisconnect","smtpSendMail","name","email","map","a","cc","bcc","replyTo","textBody","htmlBody","attachments","filename","mimeType","data","isInline","contentId","disposition","priority","headers","inReplyTo","references","readReceiptTo","undefined","charset","encoding","smtpVerifyConnection"],"sourceRoot":"..\\..\\src","sources":["native.ts"],"mappings":";;AAAA;AACA;AACA;;AAEA,SAASA,YAAY,QAAQ,4BAA4B;AAsBzD,IAAIC,YAAkC,GAAG,IAAI;AAE7C,SAASC,eAAeA,CAAA,EAAkB;EACxC,IAAI,CAACD,YAAY,EAAE;IACjBA,YAAY,GACVD,YAAY,CAACG,kBAAkB,CAAgB,eAAe,CAAC;EACnE;EACA,OAAOF,YAAY;AACrB;;AAEA;;AAEA,OAAO,eAAeG,WAAWA,CAC/BC,MAAkB,EACa;EAC/B,MAAMC,CAAC,GAAGJ,eAAe,CAAC,CAAC;EAC3B,OAAOI,CAAC,CAACF,WAAW,CAAC;IACnBG,IAAI,EAAEF,MAAM,CAACE,IAAI;IACjBC,IAAI,EAAEH,MAAM,CAACG,IAAI;IACjBC,QAAQ,EAAEJ,MAAM,CAACI,QAAQ;IACzBC,QAAQ,EAAEL,MAAM,CAACK,QAAQ;IACzBC,GAAG,EAAEN,MAAM,CAACM,GAAG,IAAI,IAAI;IACvBC,QAAQ,EAAEP,MAAM,CAACO,QAAQ,IAAI,UAAU;IACvCC,WAAW,EAAER,MAAM,CAACQ,WAAW;IAC/BC,OAAO,EAAET,MAAM,CAACS,OAAO,IAAI,KAAK;IAChCC,gBAAgB,EAAEV,MAAM,CAACU,gBAAgB,IAAI,IAAI;IACjDC,KAAK,EAAEX,MAAM,CAACW,KAAK,IAAI;
|
|
1
|
+
{"version":3,"names":["NitroModules","hybridObject","getHybridObject","createHybridObject","imapConnect","config","h","host","port","username","password","tls","authType","accessToken","timeout","checkCertificate","debug","downloadChunkSize","imapDisconnect","imapListMailboxes","imapSelectMailbox","mailbox","readOnly","imapRefreshMailbox","imapFetchFolders","imapCreateFolder","folderName","imapDeleteFolder","imapRenameFolder","oldName","newName","imapSubscribeFolder","imapUnsubscribeFolder","imapFetchEmails","options","from","to","rangeType","page","pageSize","since","before","fetchBody","fetchAttachments","fetchFlags","fetchHeaders","fetchFullContent","maxBodySize","imapFetchEmailByUID","uid","imapSearchEmails","criteria","text","subject","body","on","sentSince","sentBefore","flagged","seen","answered","draft","deleted","junk","hasAttachment","uids","header","larger","smaller","sortOrder","limit","imapMarkAsRead","silent","imapMarkAsFlagged","imapMoveEmails","destinationMailbox","imapCopyEmails","imapDeleteEmails","imapExpunge","imapFetchAttachments","partId","imapFetchAllAttachments","imapIdle","callback","imapStopIdle","imapGetQuota","root","imapAppendMessage","rawMimeData","flags","smtpConnect","helloName","smtpDisconnect","smtpSendMail","name","email","map","a","cc","bcc","replyTo","textBody","htmlBody","attachments","filename","mimeType","data","isInline","contentId","disposition","priority","headers","inReplyTo","references","readReceiptTo","undefined","charset","encoding","smtpVerifyConnection"],"sourceRoot":"..\\..\\src","sources":["native.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -18,6 +18,11 @@ export declare function moveEmails(sessionId: string, uids: number[], destinatio
|
|
|
18
18
|
export declare function copyEmails(sessionId: string, uids: number[], destinationMailbox: string): Promise<void>;
|
|
19
19
|
export declare function deleteEmails(sessionId: string, uids: number[]): Promise<any>;
|
|
20
20
|
export declare function expunge(sessionId: string): Promise<void>;
|
|
21
|
+
/** 判断错误是否为连接断开类(message + code),供路由层决定是否重连重试 */
|
|
22
|
+
export declare function isConnectionError(err: any): boolean;
|
|
23
|
+
/** 会话客户端是否已死(补充判断:message 未命中但客户端确实断了,也应重连重试)。
|
|
24
|
+
* 会话不存在或已被显式断开 → 返回 false(不该自动重连)。 */
|
|
25
|
+
export declare function isSessionClosed(sessionId: string): boolean;
|
|
21
26
|
export declare function fetchAttachment(sessionId: string, uid: number, partId: string): Promise<any | null>;
|
|
22
27
|
export declare function fetchAllAttachments(sessionId: string, uid: number): Promise<any[]>;
|
|
23
28
|
export declare function startIdle(sessionId: string, callback: (notification: any) => void): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imapHandler.d.ts","sourceRoot":"","sources":["../../../../server/src/imapHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"imapHandler.d.ts","sourceRoot":"","sources":["../../../../server/src/imapHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/src/index.ts"],"names":[],"mappings":"AAkHA,OAAO,OAAO,MAAM,SAAS,CAAC;AAO9B,QAAA,MAAM,GAAG,EAAE,OAAO,CAAC,OAAmB,CAAC;AACvC,QAAA,MAAM,MAAM,mHAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/src/index.ts"],"names":[],"mappings":"AAkHA,OAAO,OAAO,MAAM,SAAS,CAAC;AAO9B,QAAA,MAAM,GAAG,EAAE,OAAO,CAAC,OAAmB,CAAC;AACvC,QAAA,MAAM,MAAM,mHAAoB,CAAC;AA4fjC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,wBAAsB,WAAW,CAC/B,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,CAuBvB;AAQD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smtpHandler.d.ts","sourceRoot":"","sources":["../../../../server/src/smtpHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"smtpHandler.d.ts","sourceRoot":"","sources":["../../../../server/src/smtpHandler.ts"],"names":[],"mappings":"AAiEA,wBAAsB,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAyDvD;AAID,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMjE;AAmBD,wBAAsB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CA4I5E;AAID,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ1E;AAID,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C"}
|