@happyvertical/email 0.80.0 → 0.80.1
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/dist/chunks/base-sCad2IoJ.js +146 -0
- package/dist/chunks/base-sCad2IoJ.js.map +1 -0
- package/dist/cli/claude-context.js +17 -17
- package/dist/cli/claude-context.js.map +1 -1
- package/dist/index.js +1541 -2140
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,2165 +1,1566 @@
|
|
|
1
|
+
import { a as ConnectionError, c as FolderNotFoundError, d as SendError, f as TimeoutError, i as AuthorizationError, l as InvalidMessageError, n as AttachmentError, o as EmailError, r as AuthenticationError, s as FolderExistsError, t as BaseEmailClient, u as MessageNotFoundError } from "./chunks/base-sCad2IoJ.js";
|
|
1
2
|
import { google } from "googleapis";
|
|
2
3
|
import { simpleParser } from "mailparser";
|
|
3
|
-
import { createLogger } from "@happyvertical/logger";
|
|
4
4
|
import { ImapFlow } from "imapflow";
|
|
5
5
|
import Pop3Command from "node-pop3";
|
|
6
6
|
import nodemailer from "nodemailer";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
}
|
|
1404
|
-
async disconnect() {
|
|
1405
|
-
if (!this.client) {
|
|
1406
|
-
return;
|
|
1407
|
-
}
|
|
1408
|
-
try {
|
|
1409
|
-
await this.client.QUIT();
|
|
1410
|
-
this.client = null;
|
|
1411
|
-
this.connected = false;
|
|
1412
|
-
this.messageCache.clear();
|
|
1413
|
-
this.debug("Disconnected from POP3 server");
|
|
1414
|
-
} catch (error) {
|
|
1415
|
-
this.client = null;
|
|
1416
|
-
this.connected = false;
|
|
1417
|
-
this.messageCache.clear();
|
|
1418
|
-
throw this.mapPOP3Error(error);
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
// ========================================================================
|
|
1422
|
-
// Message operations
|
|
1423
|
-
// ========================================================================
|
|
1424
|
-
async fetch(options) {
|
|
1425
|
-
this.ensureConnected();
|
|
1426
|
-
try {
|
|
1427
|
-
const uidlResponse = await this.client?.UIDL();
|
|
1428
|
-
if (!uidlResponse || !uidlResponse[0]) {
|
|
1429
|
-
return [];
|
|
1430
|
-
}
|
|
1431
|
-
const uidList = this.parseUidlResponse(
|
|
1432
|
-
Array.isArray(uidlResponse[0]) ? uidlResponse[0].join("\n") : uidlResponse[0]
|
|
1433
|
-
);
|
|
1434
|
-
if (uidList.length === 0) {
|
|
1435
|
-
return [];
|
|
1436
|
-
}
|
|
1437
|
-
this.messageCache.clear();
|
|
1438
|
-
for (const { msgNum, uid } of uidList) {
|
|
1439
|
-
this.messageCache.set(msgNum, uid);
|
|
1440
|
-
}
|
|
1441
|
-
let messageNums = uidList.map((item) => item.msgNum);
|
|
1442
|
-
if (options?.offset) {
|
|
1443
|
-
messageNums = messageNums.slice(options.offset);
|
|
1444
|
-
}
|
|
1445
|
-
if (options?.limit) {
|
|
1446
|
-
messageNums = messageNums.slice(0, options.limit);
|
|
1447
|
-
}
|
|
1448
|
-
const messages = [];
|
|
1449
|
-
for (const msgNum of messageNums) {
|
|
1450
|
-
try {
|
|
1451
|
-
const message = await this.fetchMessage(msgNum);
|
|
1452
|
-
if (this.shouldIncludeMessage(message, options)) {
|
|
1453
|
-
messages.push(message);
|
|
1454
|
-
if (!this.options.leaveOnServer) {
|
|
1455
|
-
await this.deleteMessageByNum(msgNum);
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
} catch (error) {
|
|
1459
|
-
this.logger.error(`Failed to fetch message ${msgNum}:`, {
|
|
1460
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1461
|
-
});
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
return messages;
|
|
1465
|
-
} catch (error) {
|
|
1466
|
-
throw this.mapPOP3Error(error);
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
async getMessage(messageId) {
|
|
1470
|
-
this.ensureConnected();
|
|
1471
|
-
try {
|
|
1472
|
-
let msgNum = null;
|
|
1473
|
-
for (const [num, uid] of this.messageCache.entries()) {
|
|
1474
|
-
if (uid === messageId) {
|
|
1475
|
-
msgNum = num;
|
|
1476
|
-
break;
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
if (!msgNum) {
|
|
1480
|
-
const uidlResponse = await this.client?.UIDL();
|
|
1481
|
-
if (!uidlResponse || !uidlResponse[0]) {
|
|
1482
|
-
throw new MessageNotFoundError(messageId, "pop3");
|
|
1483
|
-
}
|
|
1484
|
-
const uidList = this.parseUidlResponse(
|
|
1485
|
-
Array.isArray(uidlResponse[0]) ? uidlResponse[0].join("\n") : uidlResponse[0]
|
|
1486
|
-
);
|
|
1487
|
-
this.messageCache.clear();
|
|
1488
|
-
for (const { msgNum: num, uid } of uidList) {
|
|
1489
|
-
this.messageCache.set(num, uid);
|
|
1490
|
-
if (uid === messageId) {
|
|
1491
|
-
msgNum = num;
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
if (!msgNum) {
|
|
1496
|
-
throw new MessageNotFoundError(messageId, "pop3");
|
|
1497
|
-
}
|
|
1498
|
-
return await this.fetchMessage(msgNum);
|
|
1499
|
-
} catch (error) {
|
|
1500
|
-
if (error instanceof MessageNotFoundError) {
|
|
1501
|
-
throw error;
|
|
1502
|
-
}
|
|
1503
|
-
throw this.mapPOP3Error(error);
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
async delete(messageId) {
|
|
1507
|
-
this.ensureConnected();
|
|
1508
|
-
const ids = this.normalizeMessageIds(messageId);
|
|
1509
|
-
for (const id of ids) {
|
|
1510
|
-
try {
|
|
1511
|
-
let msgNum = null;
|
|
1512
|
-
for (const [num, uid] of this.messageCache.entries()) {
|
|
1513
|
-
if (uid === id) {
|
|
1514
|
-
msgNum = num;
|
|
1515
|
-
break;
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
if (!msgNum) {
|
|
1519
|
-
const uidlResponse = await this.client?.UIDL();
|
|
1520
|
-
if (!uidlResponse || !uidlResponse[0]) {
|
|
1521
|
-
throw new MessageNotFoundError(id, "pop3");
|
|
1522
|
-
}
|
|
1523
|
-
const uidList = this.parseUidlResponse(
|
|
1524
|
-
Array.isArray(uidlResponse[0]) ? uidlResponse[0].join("\n") : uidlResponse[0]
|
|
1525
|
-
);
|
|
1526
|
-
for (const { msgNum: num, uid } of uidList) {
|
|
1527
|
-
if (uid === id) {
|
|
1528
|
-
msgNum = num;
|
|
1529
|
-
break;
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
if (!msgNum) {
|
|
1534
|
-
throw new MessageNotFoundError(id, "pop3");
|
|
1535
|
-
}
|
|
1536
|
-
await this.deleteMessageByNum(msgNum);
|
|
1537
|
-
} catch (error) {
|
|
1538
|
-
throw this.mapPOP3Error(error);
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
// ========================================================================
|
|
1543
|
-
// Unsupported operations (POP3 limitations)
|
|
1544
|
-
// ========================================================================
|
|
1545
|
-
async send(_message, _options) {
|
|
1546
|
-
throw new EmailError(
|
|
1547
|
-
"POP3 does not support sending email. Use SMTP instead.",
|
|
1548
|
-
"UNSUPPORTED_OPERATION",
|
|
1549
|
-
"pop3"
|
|
1550
|
-
);
|
|
1551
|
-
}
|
|
1552
|
-
async listFolders() {
|
|
1553
|
-
throw new EmailError(
|
|
1554
|
-
"POP3 does not support folders",
|
|
1555
|
-
"UNSUPPORTED_OPERATION",
|
|
1556
|
-
"pop3"
|
|
1557
|
-
);
|
|
1558
|
-
}
|
|
1559
|
-
async selectFolder(_name) {
|
|
1560
|
-
throw new EmailError(
|
|
1561
|
-
"POP3 does not support folders",
|
|
1562
|
-
"UNSUPPORTED_OPERATION",
|
|
1563
|
-
"pop3"
|
|
1564
|
-
);
|
|
1565
|
-
}
|
|
1566
|
-
async createFolder(_name) {
|
|
1567
|
-
throw new EmailError(
|
|
1568
|
-
"POP3 does not support folders",
|
|
1569
|
-
"UNSUPPORTED_OPERATION",
|
|
1570
|
-
"pop3"
|
|
1571
|
-
);
|
|
1572
|
-
}
|
|
1573
|
-
async deleteFolder(_name) {
|
|
1574
|
-
throw new EmailError(
|
|
1575
|
-
"POP3 does not support folders",
|
|
1576
|
-
"UNSUPPORTED_OPERATION",
|
|
1577
|
-
"pop3"
|
|
1578
|
-
);
|
|
1579
|
-
}
|
|
1580
|
-
async markRead(_messageId) {
|
|
1581
|
-
throw new EmailError(
|
|
1582
|
-
"POP3 does not support marking messages as read",
|
|
1583
|
-
"UNSUPPORTED_OPERATION",
|
|
1584
|
-
"pop3"
|
|
1585
|
-
);
|
|
1586
|
-
}
|
|
1587
|
-
async markUnread(_messageId) {
|
|
1588
|
-
throw new EmailError(
|
|
1589
|
-
"POP3 does not support marking messages as unread",
|
|
1590
|
-
"UNSUPPORTED_OPERATION",
|
|
1591
|
-
"pop3"
|
|
1592
|
-
);
|
|
1593
|
-
}
|
|
1594
|
-
async move(_messageId, _folder) {
|
|
1595
|
-
throw new EmailError(
|
|
1596
|
-
"POP3 does not support moving messages",
|
|
1597
|
-
"UNSUPPORTED_OPERATION",
|
|
1598
|
-
"pop3"
|
|
1599
|
-
);
|
|
1600
|
-
}
|
|
1601
|
-
async copy(_messageId, _folder) {
|
|
1602
|
-
throw new EmailError(
|
|
1603
|
-
"POP3 does not support copying messages",
|
|
1604
|
-
"UNSUPPORTED_OPERATION",
|
|
1605
|
-
"pop3"
|
|
1606
|
-
);
|
|
1607
|
-
}
|
|
1608
|
-
async search(_criteria) {
|
|
1609
|
-
throw new EmailError(
|
|
1610
|
-
"POP3 does not support server-side search. Use fetch() with filters instead.",
|
|
1611
|
-
"UNSUPPORTED_OPERATION",
|
|
1612
|
-
"pop3"
|
|
1613
|
-
);
|
|
1614
|
-
}
|
|
1615
|
-
// ========================================================================
|
|
1616
|
-
// Adapter info
|
|
1617
|
-
// ========================================================================
|
|
1618
|
-
async getCapabilities() {
|
|
1619
|
-
return {
|
|
1620
|
-
send: false,
|
|
1621
|
-
receive: true,
|
|
1622
|
-
folders: false,
|
|
1623
|
-
search: false,
|
|
1624
|
-
markRead: false,
|
|
1625
|
-
move: false,
|
|
1626
|
-
delete: true,
|
|
1627
|
-
threads: false,
|
|
1628
|
-
oauth: false
|
|
1629
|
-
};
|
|
1630
|
-
}
|
|
1631
|
-
getAdapter() {
|
|
1632
|
-
return "pop3";
|
|
1633
|
-
}
|
|
1634
|
-
// ========================================================================
|
|
1635
|
-
// Private helper methods
|
|
1636
|
-
// ========================================================================
|
|
1637
|
-
ensureConnected() {
|
|
1638
|
-
if (!this.connected || !this.client) {
|
|
1639
|
-
throw new ConnectionError(
|
|
1640
|
-
"Not connected to POP3 server. Call connect() first.",
|
|
1641
|
-
"pop3"
|
|
1642
|
-
);
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
async fetchMessage(msgNum) {
|
|
1646
|
-
try {
|
|
1647
|
-
const response = await this.client?.RETR(Number(msgNum));
|
|
1648
|
-
if (!response || !response[0]) {
|
|
1649
|
-
throw new Error(`Failed to retrieve message ${msgNum}`);
|
|
1650
|
-
}
|
|
1651
|
-
const messageData = response[0];
|
|
1652
|
-
const parsed = await simpleParser(messageData);
|
|
1653
|
-
const uid = this.messageCache.get(msgNum);
|
|
1654
|
-
const extractAddresses = (addressObj) => {
|
|
1655
|
-
if (!addressObj) return [];
|
|
1656
|
-
const addressArray = Array.isArray(addressObj) ? addressObj : [addressObj];
|
|
1657
|
-
const addresses = addressArray.flatMap(
|
|
1658
|
-
(obj) => Array.isArray(obj.value) ? obj.value : [obj.value]
|
|
1659
|
-
);
|
|
1660
|
-
return addresses.map((addr) => ({
|
|
1661
|
-
address: addr.address || "",
|
|
1662
|
-
name: addr.name
|
|
1663
|
-
}));
|
|
1664
|
-
};
|
|
1665
|
-
const fromAddresses = extractAddresses(parsed.from);
|
|
1666
|
-
const toAddresses = extractAddresses(parsed.to);
|
|
1667
|
-
const ccAddresses = extractAddresses(parsed.cc);
|
|
1668
|
-
const bccAddresses = extractAddresses(parsed.bcc);
|
|
1669
|
-
const replyToAddresses = extractAddresses(parsed.replyTo);
|
|
1670
|
-
return {
|
|
1671
|
-
id: uid || msgNum,
|
|
1672
|
-
messageId: parsed.messageId || uid || msgNum,
|
|
1673
|
-
from: fromAddresses[0] || { address: "", name: void 0 },
|
|
1674
|
-
to: toAddresses,
|
|
1675
|
-
cc: ccAddresses.length > 0 ? ccAddresses : void 0,
|
|
1676
|
-
bcc: bccAddresses.length > 0 ? bccAddresses : void 0,
|
|
1677
|
-
replyTo: replyToAddresses[0],
|
|
1678
|
-
subject: parsed.subject || "",
|
|
1679
|
-
date: parsed.date,
|
|
1680
|
-
text: parsed.text,
|
|
1681
|
-
html: parsed.html ? parsed.html.toString() : void 0,
|
|
1682
|
-
attachments: parsed.attachments?.map((att) => ({
|
|
1683
|
-
filename: att.filename,
|
|
1684
|
-
contentType: att.contentType,
|
|
1685
|
-
size: att.size,
|
|
1686
|
-
content: att.content,
|
|
1687
|
-
contentId: att.contentId,
|
|
1688
|
-
contentDisposition: att.contentDisposition
|
|
1689
|
-
})),
|
|
1690
|
-
headers: parsed.headers,
|
|
1691
|
-
size: messageData.length,
|
|
1692
|
-
raw: messageData
|
|
1693
|
-
};
|
|
1694
|
-
} catch (error) {
|
|
1695
|
-
throw this.mapPOP3Error(error);
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
async deleteMessageByNum(msgNum) {
|
|
1699
|
-
try {
|
|
1700
|
-
await this.client?.command(`DELE ${msgNum}`);
|
|
1701
|
-
this.messageCache.delete(msgNum);
|
|
1702
|
-
this.debug(`Deleted message ${msgNum}`);
|
|
1703
|
-
} catch (error) {
|
|
1704
|
-
throw this.mapPOP3Error(error);
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
parseUidlResponse(response) {
|
|
1708
|
-
const lines = response.split("\n");
|
|
1709
|
-
const result = [];
|
|
1710
|
-
for (const line of lines) {
|
|
1711
|
-
const trimmed = line.trim();
|
|
1712
|
-
if (!trimmed || trimmed === "." || trimmed.startsWith("+OK")) {
|
|
1713
|
-
continue;
|
|
1714
|
-
}
|
|
1715
|
-
const parts = trimmed.split(/\s+/);
|
|
1716
|
-
if (parts.length >= 2) {
|
|
1717
|
-
result.push({
|
|
1718
|
-
msgNum: parts[0],
|
|
1719
|
-
uid: parts[1]
|
|
1720
|
-
});
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
|
-
return result;
|
|
1724
|
-
}
|
|
1725
|
-
shouldIncludeMessage(message, options) {
|
|
1726
|
-
if (options?.since && message.date) {
|
|
1727
|
-
if (message.date < options.since) {
|
|
1728
|
-
return false;
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
if (options?.before && message.date) {
|
|
1732
|
-
if (message.date >= options.before) {
|
|
1733
|
-
return false;
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
return true;
|
|
1737
|
-
}
|
|
1738
|
-
mapPOP3Error(error) {
|
|
1739
|
-
if (error instanceof EmailError) {
|
|
1740
|
-
return error;
|
|
1741
|
-
}
|
|
1742
|
-
if (error instanceof Error) {
|
|
1743
|
-
const message = error.message.toLowerCase();
|
|
1744
|
-
const errorObj = error;
|
|
1745
|
-
if (message.includes("timeout") || errorObj.eventName === "timeout" || errorObj.code === "ETIMEDOUT") {
|
|
1746
|
-
return new TimeoutError(error.message, "pop3", error);
|
|
1747
|
-
}
|
|
1748
|
-
if (message.includes("connect") || message.includes("econnrefused") || message.includes("enotfound") || message.includes("ehostunreach") || errorObj.eventName === "error" || errorObj.eventName === "close" || errorObj.code === "ECONNREFUSED" || errorObj.code === "ENOTFOUND") {
|
|
1749
|
-
return new ConnectionError(error.message, "pop3", error);
|
|
1750
|
-
}
|
|
1751
|
-
if (message.includes("auth") || message.includes("login") || message.includes("password") || message.includes("user") || message.includes("-err")) {
|
|
1752
|
-
return new AuthenticationError(error.message, "pop3", error);
|
|
1753
|
-
}
|
|
1754
|
-
return new EmailError(error.message, "POP3_ERROR", "pop3", error);
|
|
1755
|
-
}
|
|
1756
|
-
return new EmailError(String(error), "POP3_ERROR", "pop3");
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
const pop3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1760
|
-
__proto__: null,
|
|
1761
|
-
POP3Adapter
|
|
1762
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
1763
|
-
class SMTPAdapter extends BaseEmailClient {
|
|
1764
|
-
transporter;
|
|
1765
|
-
options;
|
|
1766
|
-
constructor(options) {
|
|
1767
|
-
super({
|
|
1768
|
-
type: "smtp",
|
|
1769
|
-
debug: options.debug
|
|
1770
|
-
});
|
|
1771
|
-
this.options = options;
|
|
1772
|
-
this.transporter = this.createTransporter();
|
|
1773
|
-
}
|
|
1774
|
-
/**
|
|
1775
|
-
* Create Nodemailer transporter with configuration
|
|
1776
|
-
*/
|
|
1777
|
-
createTransporter() {
|
|
1778
|
-
const config = {
|
|
1779
|
-
host: this.options.host,
|
|
1780
|
-
port: this.options.port,
|
|
1781
|
-
secure: this.options.secure ?? false,
|
|
1782
|
-
auth: this.options.auth,
|
|
1783
|
-
tls: this.options.tls,
|
|
1784
|
-
connectionTimeout: this.options.connectionTimeout,
|
|
1785
|
-
greetingTimeout: this.options.greetingTimeout,
|
|
1786
|
-
socketTimeout: this.options.socketTimeout,
|
|
1787
|
-
pool: this.options.pool,
|
|
1788
|
-
maxConnections: this.options.maxConnections,
|
|
1789
|
-
maxMessages: this.options.maxMessages,
|
|
1790
|
-
debug: this.options.debug
|
|
1791
|
-
};
|
|
1792
|
-
return nodemailer.createTransport(config);
|
|
1793
|
-
}
|
|
1794
|
-
getAdapter() {
|
|
1795
|
-
return "smtp";
|
|
1796
|
-
}
|
|
1797
|
-
/**
|
|
1798
|
-
* Send an email message
|
|
1799
|
-
*/
|
|
1800
|
-
async send(message, options) {
|
|
1801
|
-
this.validateMessage(message);
|
|
1802
|
-
try {
|
|
1803
|
-
const mailOptions = {
|
|
1804
|
-
from: this.formatEmailAddress(message.from),
|
|
1805
|
-
to: message.to.map((addr) => this.formatEmailAddress(addr)),
|
|
1806
|
-
cc: message.cc?.map((addr) => this.formatEmailAddress(addr)),
|
|
1807
|
-
bcc: message.bcc?.map((addr) => this.formatEmailAddress(addr)),
|
|
1808
|
-
subject: message.subject,
|
|
1809
|
-
text: message.text,
|
|
1810
|
-
html: message.html,
|
|
1811
|
-
replyTo: message.replyTo ? this.formatEmailAddress(message.replyTo) : void 0,
|
|
1812
|
-
inReplyTo: message.inReplyTo,
|
|
1813
|
-
references: message.references,
|
|
1814
|
-
attachments: message.attachments?.map((att) => ({
|
|
1815
|
-
filename: att.filename,
|
|
1816
|
-
content: att.content,
|
|
1817
|
-
path: att.path,
|
|
1818
|
-
contentType: att.contentType,
|
|
1819
|
-
cid: att.contentId,
|
|
1820
|
-
contentDisposition: att.contentDisposition
|
|
1821
|
-
})),
|
|
1822
|
-
headers: message.headers,
|
|
1823
|
-
messageId: message.messageId || options?.messageId,
|
|
1824
|
-
date: message.date || options?.date,
|
|
1825
|
-
encoding: options?.encoding,
|
|
1826
|
-
textEncoding: options?.textEncoding,
|
|
1827
|
-
envelope: options?.envelope,
|
|
1828
|
-
priority: options?.priority,
|
|
1829
|
-
dsn: options?.dsn
|
|
1830
|
-
};
|
|
1831
|
-
this.debug("Sending email", {
|
|
1832
|
-
to: mailOptions.to,
|
|
1833
|
-
subject: message.subject
|
|
1834
|
-
});
|
|
1835
|
-
const info = await this.transporter.sendMail(mailOptions);
|
|
1836
|
-
const sendInfo = info;
|
|
1837
|
-
return {
|
|
1838
|
-
messageId: sendInfo.messageId,
|
|
1839
|
-
accepted: sendInfo.accepted,
|
|
1840
|
-
rejected: sendInfo.rejected,
|
|
1841
|
-
response: sendInfo.response
|
|
1842
|
-
};
|
|
1843
|
-
} catch (error) {
|
|
1844
|
-
throw this.mapSMTPError(error);
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
/**
|
|
1848
|
-
* Format email address for Nodemailer
|
|
1849
|
-
*/
|
|
1850
|
-
formatEmailAddress(addr) {
|
|
1851
|
-
if (addr.name) {
|
|
1852
|
-
const name = addr.name.replace(/"/g, '\\"');
|
|
1853
|
-
return `"${name}" <${addr.address}>`;
|
|
1854
|
-
}
|
|
1855
|
-
return addr.address;
|
|
1856
|
-
}
|
|
1857
|
-
/**
|
|
1858
|
-
* Map Nodemailer/SMTP errors to standard error types
|
|
1859
|
-
*/
|
|
1860
|
-
mapSMTPError(error) {
|
|
1861
|
-
if (error instanceof EmailError) {
|
|
1862
|
-
return error;
|
|
1863
|
-
}
|
|
1864
|
-
if (error instanceof Error) {
|
|
1865
|
-
const message = error.message.toLowerCase();
|
|
1866
|
-
if (message.includes("authentication") || message.includes("invalid login") || message.includes("535")) {
|
|
1867
|
-
return new AuthenticationError(error.message, "smtp", error);
|
|
1868
|
-
}
|
|
1869
|
-
if (message.includes("timeout") || message.includes("etimedout")) {
|
|
1870
|
-
return new TimeoutError(error.message, "smtp", error);
|
|
1871
|
-
}
|
|
1872
|
-
if (message.includes("econnrefused") || message.includes("enotfound") || message.includes("connection") || message.includes("ehostunreach")) {
|
|
1873
|
-
return new ConnectionError(error.message, "smtp", error);
|
|
1874
|
-
}
|
|
1875
|
-
if ("accepted" in error && "rejected" in error) {
|
|
1876
|
-
const errorWithRecipients = error;
|
|
1877
|
-
return new SendError(
|
|
1878
|
-
error.message,
|
|
1879
|
-
errorWithRecipients.accepted || [],
|
|
1880
|
-
errorWithRecipients.rejected || [],
|
|
1881
|
-
"smtp",
|
|
1882
|
-
error
|
|
1883
|
-
);
|
|
1884
|
-
}
|
|
1885
|
-
return new EmailError(error.message, "SMTP_ERROR", "smtp", error);
|
|
1886
|
-
}
|
|
1887
|
-
return new EmailError(String(error), "UNKNOWN_ERROR", "smtp");
|
|
1888
|
-
}
|
|
1889
|
-
/**
|
|
1890
|
-
* Connect to SMTP server (verify connection)
|
|
1891
|
-
*/
|
|
1892
|
-
async connect() {
|
|
1893
|
-
try {
|
|
1894
|
-
this.debug("Verifying SMTP connection", { host: this.options.host });
|
|
1895
|
-
await this.transporter.verify();
|
|
1896
|
-
this.connected = true;
|
|
1897
|
-
this.debug("SMTP connection verified");
|
|
1898
|
-
} catch (error) {
|
|
1899
|
-
this.connected = false;
|
|
1900
|
-
throw this.mapSMTPError(error);
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
/**
|
|
1904
|
-
* Disconnect from SMTP server
|
|
1905
|
-
*/
|
|
1906
|
-
async disconnect() {
|
|
1907
|
-
this.transporter.close();
|
|
1908
|
-
this.connected = false;
|
|
1909
|
-
this.debug("SMTP connection closed");
|
|
1910
|
-
}
|
|
1911
|
-
/**
|
|
1912
|
-
* Get adapter capabilities
|
|
1913
|
-
*/
|
|
1914
|
-
async getCapabilities() {
|
|
1915
|
-
return {
|
|
1916
|
-
send: true,
|
|
1917
|
-
receive: false,
|
|
1918
|
-
// SMTP is send-only
|
|
1919
|
-
folders: false,
|
|
1920
|
-
search: false,
|
|
1921
|
-
markRead: false,
|
|
1922
|
-
move: false,
|
|
1923
|
-
delete: false,
|
|
1924
|
-
threads: false,
|
|
1925
|
-
oauth: this.isOAuth2()
|
|
1926
|
-
};
|
|
1927
|
-
}
|
|
1928
|
-
/**
|
|
1929
|
-
* Check if using OAuth2 authentication
|
|
1930
|
-
*/
|
|
1931
|
-
isOAuth2() {
|
|
1932
|
-
return this.options.auth !== void 0 && "type" in this.options.auth && this.options.auth.type === "OAuth2";
|
|
1933
|
-
}
|
|
1934
|
-
// ========================================================================
|
|
1935
|
-
// Unsupported operations (SMTP is send-only)
|
|
1936
|
-
// ========================================================================
|
|
1937
|
-
async fetch(_options) {
|
|
1938
|
-
throw new EmailError(
|
|
1939
|
-
"SMTP does not support receiving messages. Use IMAP or POP3 adapter.",
|
|
1940
|
-
"UNSUPPORTED_OPERATION",
|
|
1941
|
-
"smtp"
|
|
1942
|
-
);
|
|
1943
|
-
}
|
|
1944
|
-
async getMessage(_messageId) {
|
|
1945
|
-
throw new EmailError(
|
|
1946
|
-
"SMTP does not support receiving messages. Use IMAP or POP3 adapter.",
|
|
1947
|
-
"UNSUPPORTED_OPERATION",
|
|
1948
|
-
"smtp"
|
|
1949
|
-
);
|
|
1950
|
-
}
|
|
1951
|
-
async listFolders() {
|
|
1952
|
-
throw new EmailError(
|
|
1953
|
-
"SMTP does not support folder operations.",
|
|
1954
|
-
"UNSUPPORTED_OPERATION",
|
|
1955
|
-
"smtp"
|
|
1956
|
-
);
|
|
1957
|
-
}
|
|
1958
|
-
async selectFolder(_name) {
|
|
1959
|
-
throw new EmailError(
|
|
1960
|
-
"SMTP does not support folder operations.",
|
|
1961
|
-
"UNSUPPORTED_OPERATION",
|
|
1962
|
-
"smtp"
|
|
1963
|
-
);
|
|
1964
|
-
}
|
|
1965
|
-
async createFolder(_name) {
|
|
1966
|
-
throw new EmailError(
|
|
1967
|
-
"SMTP does not support folder operations.",
|
|
1968
|
-
"UNSUPPORTED_OPERATION",
|
|
1969
|
-
"smtp"
|
|
1970
|
-
);
|
|
1971
|
-
}
|
|
1972
|
-
async deleteFolder(_name) {
|
|
1973
|
-
throw new EmailError(
|
|
1974
|
-
"SMTP does not support folder operations.",
|
|
1975
|
-
"UNSUPPORTED_OPERATION",
|
|
1976
|
-
"smtp"
|
|
1977
|
-
);
|
|
1978
|
-
}
|
|
1979
|
-
async markRead(_messageId) {
|
|
1980
|
-
throw new EmailError(
|
|
1981
|
-
"SMTP does not support message operations.",
|
|
1982
|
-
"UNSUPPORTED_OPERATION",
|
|
1983
|
-
"smtp"
|
|
1984
|
-
);
|
|
1985
|
-
}
|
|
1986
|
-
async markUnread(_messageId) {
|
|
1987
|
-
throw new EmailError(
|
|
1988
|
-
"SMTP does not support message operations.",
|
|
1989
|
-
"UNSUPPORTED_OPERATION",
|
|
1990
|
-
"smtp"
|
|
1991
|
-
);
|
|
1992
|
-
}
|
|
1993
|
-
async move(_messageId, _folder) {
|
|
1994
|
-
throw new EmailError(
|
|
1995
|
-
"SMTP does not support message operations.",
|
|
1996
|
-
"UNSUPPORTED_OPERATION",
|
|
1997
|
-
"smtp"
|
|
1998
|
-
);
|
|
1999
|
-
}
|
|
2000
|
-
async copy(_messageId, _folder) {
|
|
2001
|
-
throw new EmailError(
|
|
2002
|
-
"SMTP does not support message operations.",
|
|
2003
|
-
"UNSUPPORTED_OPERATION",
|
|
2004
|
-
"smtp"
|
|
2005
|
-
);
|
|
2006
|
-
}
|
|
2007
|
-
async delete(_messageId) {
|
|
2008
|
-
throw new EmailError(
|
|
2009
|
-
"SMTP does not support message operations.",
|
|
2010
|
-
"UNSUPPORTED_OPERATION",
|
|
2011
|
-
"smtp"
|
|
2012
|
-
);
|
|
2013
|
-
}
|
|
2014
|
-
async search(_criteria) {
|
|
2015
|
-
throw new EmailError(
|
|
2016
|
-
"SMTP does not support search operations.",
|
|
2017
|
-
"UNSUPPORTED_OPERATION",
|
|
2018
|
-
"smtp"
|
|
2019
|
-
);
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
const smtp = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2023
|
-
__proto__: null,
|
|
2024
|
-
SMTPAdapter
|
|
2025
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
7
|
+
//#region \0rolldown/runtime.js
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __exportAll = (all, no_symbols) => {
|
|
10
|
+
let target = {};
|
|
11
|
+
for (var name in all) __defProp(target, name, {
|
|
12
|
+
get: all[name],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
16
|
+
return target;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/adapters/gmail.ts
|
|
20
|
+
var gmail_exports = /* @__PURE__ */ __exportAll({ GmailAdapter: () => GmailAdapter });
|
|
21
|
+
/**
|
|
22
|
+
* Gmail adapter implementation using Gmail API
|
|
23
|
+
*
|
|
24
|
+
* Requires OAuth2 credentials with appropriate scopes:
|
|
25
|
+
* - gmail.readonly: Read emails and settings
|
|
26
|
+
* - gmail.send: Send emails
|
|
27
|
+
* - gmail.modify: Modify emails (mark read, delete, move)
|
|
28
|
+
* - gmail.labels: Manage labels
|
|
29
|
+
*/
|
|
30
|
+
var GmailAdapter = class extends BaseEmailClient {
|
|
31
|
+
gmail = null;
|
|
32
|
+
options;
|
|
33
|
+
auth = null;
|
|
34
|
+
constructor(options) {
|
|
35
|
+
super({
|
|
36
|
+
type: "gmail",
|
|
37
|
+
debug: options.debug
|
|
38
|
+
});
|
|
39
|
+
this.options = options;
|
|
40
|
+
}
|
|
41
|
+
async connect() {
|
|
42
|
+
try {
|
|
43
|
+
const auth = new google.auth.OAuth2(this.options.auth.clientId, this.options.auth.clientSecret);
|
|
44
|
+
auth.setCredentials({
|
|
45
|
+
refresh_token: this.options.auth.refreshToken,
|
|
46
|
+
access_token: this.options.auth.accessToken
|
|
47
|
+
});
|
|
48
|
+
this.auth = auth;
|
|
49
|
+
this.gmail = google.gmail({
|
|
50
|
+
version: "v1",
|
|
51
|
+
auth
|
|
52
|
+
});
|
|
53
|
+
await this.gmail.users.getProfile({ userId: this.getUserId() });
|
|
54
|
+
this.connected = true;
|
|
55
|
+
this.debug("Connected to Gmail API");
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw this.mapGmailError(error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async disconnect() {
|
|
61
|
+
this.gmail = null;
|
|
62
|
+
this.auth = null;
|
|
63
|
+
this.connected = false;
|
|
64
|
+
this.debug("Disconnected from Gmail API");
|
|
65
|
+
}
|
|
66
|
+
async send(message, options) {
|
|
67
|
+
this.ensureConnected();
|
|
68
|
+
this.validateMessage(message);
|
|
69
|
+
try {
|
|
70
|
+
const email = this.buildRFC2822Message(message, options);
|
|
71
|
+
const encodedEmail = Buffer.from(email).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
72
|
+
const response = await this.gmail?.users.messages.send({
|
|
73
|
+
userId: this.getUserId(),
|
|
74
|
+
requestBody: { raw: encodedEmail }
|
|
75
|
+
});
|
|
76
|
+
if (!response) throw new SendError("Failed to send message", [], [], "gmail");
|
|
77
|
+
return {
|
|
78
|
+
messageId: response.data.id || "",
|
|
79
|
+
accepted: message.to.map((addr) => addr.address),
|
|
80
|
+
rejected: [],
|
|
81
|
+
response: `Message sent: ${response.data.id}`
|
|
82
|
+
};
|
|
83
|
+
} catch (error) {
|
|
84
|
+
throw this.mapGmailError(error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async fetch(options) {
|
|
88
|
+
this.ensureConnected();
|
|
89
|
+
try {
|
|
90
|
+
const query = this.buildGmailQuery(options);
|
|
91
|
+
let labelIds = options?.labelIds;
|
|
92
|
+
if (options?.folder && !labelIds) labelIds = [options.folder];
|
|
93
|
+
let listResponse;
|
|
94
|
+
try {
|
|
95
|
+
listResponse = await this.gmail?.users.messages.list({
|
|
96
|
+
userId: this.getUserId(),
|
|
97
|
+
q: query,
|
|
98
|
+
labelIds,
|
|
99
|
+
maxResults: options?.maxResults || options?.limit || 100
|
|
100
|
+
});
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (error instanceof Error && error.message.includes("Invalid label")) return [];
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
if (!listResponse) return [];
|
|
106
|
+
const messageIds = listResponse.data.messages || [];
|
|
107
|
+
if (messageIds.length === 0) return [];
|
|
108
|
+
const messages = [];
|
|
109
|
+
for (const msgId of messageIds) {
|
|
110
|
+
if (!msgId.id) continue;
|
|
111
|
+
try {
|
|
112
|
+
const message = await this.getMessage(msgId.id);
|
|
113
|
+
messages.push(message);
|
|
114
|
+
if (options?.limit && messages.length >= options.limit) break;
|
|
115
|
+
} catch (error) {
|
|
116
|
+
this.logger.error(`Failed to fetch message ${msgId.id}:`, { error: error instanceof Error ? error.message : String(error) });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return messages;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
throw this.mapGmailError(error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async getMessage(messageId) {
|
|
125
|
+
this.ensureConnected();
|
|
126
|
+
try {
|
|
127
|
+
const response = await this.gmail?.users.messages.get({
|
|
128
|
+
userId: this.getUserId(),
|
|
129
|
+
id: messageId,
|
|
130
|
+
format: "raw"
|
|
131
|
+
});
|
|
132
|
+
if (!response || !response.data.raw) throw new MessageNotFoundError(messageId, "gmail");
|
|
133
|
+
const rawMessage = Buffer.from(response.data.raw, "base64").toString("utf-8");
|
|
134
|
+
const parsed = await simpleParser(rawMessage);
|
|
135
|
+
const labels = response.data.labelIds || [];
|
|
136
|
+
const extractAddresses = (addressObj) => {
|
|
137
|
+
if (!addressObj) return [];
|
|
138
|
+
return (Array.isArray(addressObj) ? addressObj : [addressObj]).flatMap((obj) => Array.isArray(obj.value) ? obj.value : [obj.value]).map((addr) => ({
|
|
139
|
+
address: addr.address || "",
|
|
140
|
+
name: addr.name
|
|
141
|
+
}));
|
|
142
|
+
};
|
|
143
|
+
const fromAddresses = extractAddresses(parsed.from);
|
|
144
|
+
const toAddresses = extractAddresses(parsed.to);
|
|
145
|
+
const ccAddresses = extractAddresses(parsed.cc);
|
|
146
|
+
const bccAddresses = extractAddresses(parsed.bcc);
|
|
147
|
+
const replyToAddresses = extractAddresses(parsed.replyTo);
|
|
148
|
+
return {
|
|
149
|
+
id: response.data.id || void 0,
|
|
150
|
+
messageId: parsed.messageId || response.data.id || void 0,
|
|
151
|
+
threadId: response.data.threadId || void 0,
|
|
152
|
+
inReplyTo: parsed.inReplyTo,
|
|
153
|
+
references: parsed.references ? Array.isArray(parsed.references) ? parsed.references : [parsed.references] : void 0,
|
|
154
|
+
from: fromAddresses[0] || {
|
|
155
|
+
address: "",
|
|
156
|
+
name: void 0
|
|
157
|
+
},
|
|
158
|
+
to: toAddresses,
|
|
159
|
+
cc: ccAddresses.length > 0 ? ccAddresses : void 0,
|
|
160
|
+
bcc: bccAddresses.length > 0 ? bccAddresses : void 0,
|
|
161
|
+
replyTo: replyToAddresses[0],
|
|
162
|
+
subject: parsed.subject || "",
|
|
163
|
+
date: parsed.date,
|
|
164
|
+
text: parsed.text,
|
|
165
|
+
html: parsed.html ? parsed.html.toString() : void 0,
|
|
166
|
+
attachments: parsed.attachments?.map((att) => ({
|
|
167
|
+
filename: att.filename,
|
|
168
|
+
contentType: att.contentType,
|
|
169
|
+
size: att.size,
|
|
170
|
+
content: att.content,
|
|
171
|
+
contentId: att.contentId,
|
|
172
|
+
contentDisposition: att.contentDisposition
|
|
173
|
+
})),
|
|
174
|
+
labels,
|
|
175
|
+
headers: parsed.headers,
|
|
176
|
+
size: Number(response.data.sizeEstimate),
|
|
177
|
+
raw: rawMessage
|
|
178
|
+
};
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (error instanceof MessageNotFoundError) throw error;
|
|
181
|
+
throw this.mapGmailError(error);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async listFolders() {
|
|
185
|
+
this.ensureConnected();
|
|
186
|
+
try {
|
|
187
|
+
const response = await this.gmail?.users.labels.list({ userId: this.getUserId() });
|
|
188
|
+
if (!response) return [];
|
|
189
|
+
return (response.data.labels || []).map((label) => ({
|
|
190
|
+
name: label.name || "",
|
|
191
|
+
path: label.id || "",
|
|
192
|
+
delimiter: "/",
|
|
193
|
+
specialUse: this.mapGmailLabelToSpecialUse(label.type),
|
|
194
|
+
messageCount: label.messagesTotal || void 0,
|
|
195
|
+
unreadCount: label.messagesUnread || void 0
|
|
196
|
+
}));
|
|
197
|
+
} catch (error) {
|
|
198
|
+
throw this.mapGmailError(error);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async selectFolder(name) {
|
|
202
|
+
this.ensureConnected();
|
|
203
|
+
try {
|
|
204
|
+
const label = (await this.listFolders()).find((l) => l.name === name || l.path === name);
|
|
205
|
+
if (!label) throw new FolderNotFoundError(name, "gmail");
|
|
206
|
+
return {
|
|
207
|
+
name: label.name,
|
|
208
|
+
exists: label.messageCount || 0,
|
|
209
|
+
recent: 0,
|
|
210
|
+
unseen: label.unreadCount || 0,
|
|
211
|
+
uidValidity: 0,
|
|
212
|
+
uidNext: 0,
|
|
213
|
+
flags: [],
|
|
214
|
+
permanentFlags: []
|
|
215
|
+
};
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if (error instanceof FolderNotFoundError) throw error;
|
|
218
|
+
throw this.mapGmailError(error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async createFolder(name) {
|
|
222
|
+
this.ensureConnected();
|
|
223
|
+
try {
|
|
224
|
+
if ((await this.listFolders()).some((l) => l.name === name)) throw new FolderExistsError(name, "gmail");
|
|
225
|
+
await this.gmail?.users.labels.create({
|
|
226
|
+
userId: this.getUserId(),
|
|
227
|
+
requestBody: {
|
|
228
|
+
name,
|
|
229
|
+
labelListVisibility: "labelShow",
|
|
230
|
+
messageListVisibility: "show"
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
} catch (error) {
|
|
234
|
+
if (error instanceof FolderExistsError) throw error;
|
|
235
|
+
throw this.mapGmailError(error);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async deleteFolder(name) {
|
|
239
|
+
this.ensureConnected();
|
|
240
|
+
try {
|
|
241
|
+
const label = (await this.listFolders()).find((l) => l.name === name);
|
|
242
|
+
if (!label) throw new FolderNotFoundError(name, "gmail");
|
|
243
|
+
if (label.specialUse) throw new EmailError(`Cannot delete system label: ${name}`, "INVALID_OPERATION", "gmail");
|
|
244
|
+
await this.gmail?.users.labels.delete({
|
|
245
|
+
userId: this.getUserId(),
|
|
246
|
+
id: label.path
|
|
247
|
+
});
|
|
248
|
+
} catch (error) {
|
|
249
|
+
if (error instanceof FolderNotFoundError || error instanceof EmailError) throw error;
|
|
250
|
+
throw this.mapGmailError(error);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async markRead(messageId) {
|
|
254
|
+
this.ensureConnected();
|
|
255
|
+
const ids = this.normalizeMessageIds(messageId);
|
|
256
|
+
try {
|
|
257
|
+
for (const id of ids) await this.gmail?.users.messages.modify({
|
|
258
|
+
userId: this.getUserId(),
|
|
259
|
+
id,
|
|
260
|
+
requestBody: { removeLabelIds: ["UNREAD"] }
|
|
261
|
+
});
|
|
262
|
+
} catch (error) {
|
|
263
|
+
throw this.mapGmailError(error);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
async markUnread(messageId) {
|
|
267
|
+
this.ensureConnected();
|
|
268
|
+
const ids = this.normalizeMessageIds(messageId);
|
|
269
|
+
try {
|
|
270
|
+
for (const id of ids) await this.gmail?.users.messages.modify({
|
|
271
|
+
userId: this.getUserId(),
|
|
272
|
+
id,
|
|
273
|
+
requestBody: { addLabelIds: ["UNREAD"] }
|
|
274
|
+
});
|
|
275
|
+
} catch (error) {
|
|
276
|
+
throw this.mapGmailError(error);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async move(messageId, folder) {
|
|
280
|
+
this.ensureConnected();
|
|
281
|
+
const ids = this.normalizeMessageIds(messageId);
|
|
282
|
+
try {
|
|
283
|
+
const label = (await this.listFolders()).find((l) => l.name === folder || l.path === folder);
|
|
284
|
+
if (!label) throw new FolderNotFoundError(folder, "gmail");
|
|
285
|
+
for (const id of ids) await this.gmail?.users.messages.modify({
|
|
286
|
+
userId: this.getUserId(),
|
|
287
|
+
id,
|
|
288
|
+
requestBody: { addLabelIds: [label.path] }
|
|
289
|
+
});
|
|
290
|
+
} catch (error) {
|
|
291
|
+
if (error instanceof FolderNotFoundError) throw error;
|
|
292
|
+
throw this.mapGmailError(error);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async copy(messageId, folder) {
|
|
296
|
+
await this.move(messageId, folder);
|
|
297
|
+
}
|
|
298
|
+
async delete(messageId) {
|
|
299
|
+
this.ensureConnected();
|
|
300
|
+
const ids = this.normalizeMessageIds(messageId);
|
|
301
|
+
try {
|
|
302
|
+
for (const id of ids) await this.gmail?.users.messages.trash({
|
|
303
|
+
userId: this.getUserId(),
|
|
304
|
+
id
|
|
305
|
+
});
|
|
306
|
+
} catch (error) {
|
|
307
|
+
throw this.mapGmailError(error);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async search(criteria) {
|
|
311
|
+
this.ensureConnected();
|
|
312
|
+
try {
|
|
313
|
+
if (criteria.q) return await this.fetch({ q: criteria.q });
|
|
314
|
+
const queryParts = [];
|
|
315
|
+
if (criteria.from) queryParts.push(`from:${criteria.from}`);
|
|
316
|
+
if (criteria.to) queryParts.push(`to:${criteria.to}`);
|
|
317
|
+
if (criteria.subject) queryParts.push(`subject:${criteria.subject}`);
|
|
318
|
+
if (criteria.body) queryParts.push(criteria.body);
|
|
319
|
+
if (criteria.since) queryParts.push(`after:${this.formatGmailDate(criteria.since)}`);
|
|
320
|
+
if (criteria.before) queryParts.push(`before:${this.formatGmailDate(criteria.before)}`);
|
|
321
|
+
if (criteria.unread === true) queryParts.push("is:unread");
|
|
322
|
+
if (criteria.unread === false) queryParts.push("is:read");
|
|
323
|
+
if (criteria.flagged) queryParts.push("is:starred");
|
|
324
|
+
if (criteria.larger) queryParts.push(`larger:${criteria.larger}`);
|
|
325
|
+
if (criteria.smaller) queryParts.push(`smaller:${criteria.smaller}`);
|
|
326
|
+
const query = queryParts.join(" ");
|
|
327
|
+
return await this.fetch({ q: query });
|
|
328
|
+
} catch (error) {
|
|
329
|
+
throw this.mapGmailError(error);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async getCapabilities() {
|
|
333
|
+
return {
|
|
334
|
+
send: true,
|
|
335
|
+
receive: true,
|
|
336
|
+
folders: true,
|
|
337
|
+
search: true,
|
|
338
|
+
markRead: true,
|
|
339
|
+
move: true,
|
|
340
|
+
delete: true,
|
|
341
|
+
threads: true,
|
|
342
|
+
oauth: true
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
getAdapter() {
|
|
346
|
+
return "gmail";
|
|
347
|
+
}
|
|
348
|
+
ensureConnected() {
|
|
349
|
+
if (!this.connected || !this.gmail) throw new ConnectionError("Not connected to Gmail. Call connect() first.", "gmail");
|
|
350
|
+
}
|
|
351
|
+
getUserId() {
|
|
352
|
+
return this.options.userId || "me";
|
|
353
|
+
}
|
|
354
|
+
buildRFC2822Message(message, options) {
|
|
355
|
+
const lines = [];
|
|
356
|
+
const hasAttachments = message.attachments && message.attachments.length > 0;
|
|
357
|
+
lines.push(`From: ${this.formatEmailAddress(message.from)}`);
|
|
358
|
+
lines.push(`To: ${message.to.map((a) => this.formatEmailAddress(a)).join(", ")}`);
|
|
359
|
+
if (message.cc && message.cc.length > 0) lines.push(`Cc: ${message.cc.map((a) => this.formatEmailAddress(a)).join(", ")}`);
|
|
360
|
+
if (message.replyTo) lines.push(`Reply-To: ${this.formatEmailAddress(message.replyTo)}`);
|
|
361
|
+
lines.push(`Subject: ${message.subject}`);
|
|
362
|
+
lines.push(`Date: ${options?.date?.toUTCString() || (/* @__PURE__ */ new Date()).toUTCString()}`);
|
|
363
|
+
if (options?.messageId) lines.push(`Message-ID: <${options.messageId}>`);
|
|
364
|
+
lines.push("MIME-Version: 1.0");
|
|
365
|
+
if (hasAttachments) {
|
|
366
|
+
lines.push("Content-Type: multipart/mixed; boundary=\"mixed-boundary\"");
|
|
367
|
+
lines.push("");
|
|
368
|
+
lines.push("--mixed-boundary");
|
|
369
|
+
if (message.html) {
|
|
370
|
+
lines.push("Content-Type: multipart/alternative; boundary=\"alt-boundary\"");
|
|
371
|
+
lines.push("");
|
|
372
|
+
lines.push("--alt-boundary");
|
|
373
|
+
lines.push("Content-Type: text/plain; charset=\"UTF-8\"");
|
|
374
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
375
|
+
lines.push("");
|
|
376
|
+
lines.push(message.text || "");
|
|
377
|
+
lines.push("");
|
|
378
|
+
lines.push("--alt-boundary");
|
|
379
|
+
lines.push("Content-Type: text/html; charset=\"UTF-8\"");
|
|
380
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
381
|
+
lines.push("");
|
|
382
|
+
lines.push(message.html);
|
|
383
|
+
lines.push("");
|
|
384
|
+
lines.push("--alt-boundary--");
|
|
385
|
+
} else {
|
|
386
|
+
lines.push("Content-Type: text/plain; charset=\"UTF-8\"");
|
|
387
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
388
|
+
lines.push("");
|
|
389
|
+
lines.push(message.text || "");
|
|
390
|
+
}
|
|
391
|
+
if (message.attachments) for (const attachment of message.attachments) {
|
|
392
|
+
lines.push("");
|
|
393
|
+
lines.push("--mixed-boundary");
|
|
394
|
+
lines.push(`Content-Type: ${attachment.contentType}; name="${attachment.filename}"`);
|
|
395
|
+
lines.push("Content-Transfer-Encoding: base64");
|
|
396
|
+
lines.push(`Content-Disposition: ${attachment.contentDisposition || "attachment"}; filename="${attachment.filename}"`);
|
|
397
|
+
if (attachment.contentId) lines.push(`Content-ID: <${attachment.contentId}>`);
|
|
398
|
+
lines.push("");
|
|
399
|
+
const base64Lines = (attachment.content || Buffer.from("")).toString("base64").match(/.{1,76}/g) || [];
|
|
400
|
+
lines.push(...base64Lines);
|
|
401
|
+
}
|
|
402
|
+
lines.push("");
|
|
403
|
+
lines.push("--mixed-boundary--");
|
|
404
|
+
} else if (message.html) {
|
|
405
|
+
lines.push("Content-Type: multipart/alternative; boundary=\"alt-boundary\"");
|
|
406
|
+
lines.push("");
|
|
407
|
+
lines.push("--alt-boundary");
|
|
408
|
+
lines.push("Content-Type: text/plain; charset=\"UTF-8\"");
|
|
409
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
410
|
+
lines.push("");
|
|
411
|
+
lines.push(message.text || "");
|
|
412
|
+
lines.push("");
|
|
413
|
+
lines.push("--alt-boundary");
|
|
414
|
+
lines.push("Content-Type: text/html; charset=\"UTF-8\"");
|
|
415
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
416
|
+
lines.push("");
|
|
417
|
+
lines.push(message.html);
|
|
418
|
+
lines.push("");
|
|
419
|
+
lines.push("--alt-boundary--");
|
|
420
|
+
} else {
|
|
421
|
+
lines.push("Content-Type: text/plain; charset=\"UTF-8\"");
|
|
422
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
423
|
+
lines.push("");
|
|
424
|
+
lines.push(message.text || "");
|
|
425
|
+
}
|
|
426
|
+
return lines.join("\r\n");
|
|
427
|
+
}
|
|
428
|
+
formatEmailAddress(addr) {
|
|
429
|
+
if (addr.name) return `${addr.name} <${addr.address}>`;
|
|
430
|
+
return addr.address;
|
|
431
|
+
}
|
|
432
|
+
buildGmailQuery(options) {
|
|
433
|
+
const queryParts = [];
|
|
434
|
+
if (options?.q) return options.q;
|
|
435
|
+
if (options?.since) queryParts.push(`after:${this.formatGmailDate(options.since)}`);
|
|
436
|
+
if (options?.before) queryParts.push(`before:${this.formatGmailDate(options.before)}`);
|
|
437
|
+
if (options?.unreadOnly) queryParts.push("is:unread");
|
|
438
|
+
return queryParts.join(" ");
|
|
439
|
+
}
|
|
440
|
+
formatGmailDate(date) {
|
|
441
|
+
return `${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, "0")}/${String(date.getDate()).padStart(2, "0")}`;
|
|
442
|
+
}
|
|
443
|
+
mapGmailLabelToSpecialUse(type) {
|
|
444
|
+
switch (type) {
|
|
445
|
+
case "system": return "\\Inbox";
|
|
446
|
+
default: return;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
mapGmailError(error) {
|
|
450
|
+
if (error instanceof EmailError) return error;
|
|
451
|
+
if (error instanceof Error) {
|
|
452
|
+
const message = error.message.toLowerCase();
|
|
453
|
+
const errorObj = error;
|
|
454
|
+
if (message.includes("timeout") || errorObj.code === "ETIMEDOUT" || errorObj.code === "ESOCKETTIMEDOUT") return new TimeoutError(error.message, "gmail", error);
|
|
455
|
+
if (message.includes("network") || message.includes("connect") || errorObj.code === "ECONNREFUSED" || errorObj.code === "ENOTFOUND" || errorObj.code === "ECONNRESET") return new ConnectionError(error.message, "gmail", error);
|
|
456
|
+
if (message.includes("auth") || message.includes("invalid_grant") || message.includes("unauthorized") || errorObj.code === 401) return new AuthenticationError(error.message, "gmail", error);
|
|
457
|
+
if (message.includes("recipient") || message.includes("invalid email")) return new SendError(error.message, [], [], "gmail", error);
|
|
458
|
+
return new EmailError(error.message, "GMAIL_ERROR", "gmail", error);
|
|
459
|
+
}
|
|
460
|
+
return new EmailError(String(error), "GMAIL_ERROR", "gmail");
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/adapters/imap.ts
|
|
465
|
+
var imap_exports = /* @__PURE__ */ __exportAll({ IMAPAdapter: () => IMAPAdapter });
|
|
466
|
+
/**
|
|
467
|
+
* IMAP adapter for receiving email via IMAP protocol
|
|
468
|
+
*
|
|
469
|
+
* Uses ImapFlow for robust IMAP operations including:
|
|
470
|
+
* - Fetch messages with various filters
|
|
471
|
+
* - Folder management (list, create, delete, rename)
|
|
472
|
+
* - Message operations (mark read, move, copy, delete)
|
|
473
|
+
* - Search functionality
|
|
474
|
+
* - OAuth2 authentication
|
|
475
|
+
* - IDLE push notifications (optional)
|
|
476
|
+
*/
|
|
477
|
+
var IMAPAdapter = class extends BaseEmailClient {
|
|
478
|
+
client = null;
|
|
479
|
+
options;
|
|
480
|
+
currentFolder = null;
|
|
481
|
+
constructor(options) {
|
|
482
|
+
super({
|
|
483
|
+
type: "imap",
|
|
484
|
+
debug: options.debug
|
|
485
|
+
});
|
|
486
|
+
this.options = options;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Create ImapFlow client
|
|
490
|
+
*/
|
|
491
|
+
createClient() {
|
|
492
|
+
return new ImapFlow({
|
|
493
|
+
host: this.options.host,
|
|
494
|
+
port: this.options.port,
|
|
495
|
+
secure: this.options.secure ?? true,
|
|
496
|
+
auth: this.options.auth,
|
|
497
|
+
tls: this.options.tls,
|
|
498
|
+
logger: this.options.debug ? {
|
|
499
|
+
debug: (msg) => this.debug(msg),
|
|
500
|
+
info: (msg) => this.debug(msg),
|
|
501
|
+
warn: (msg) => this.debug(`WARN: ${msg}`),
|
|
502
|
+
error: (msg) => this.debug(`ERROR: ${msg}`)
|
|
503
|
+
} : false
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
getAdapter() {
|
|
507
|
+
return "imap";
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Helper to convert search results to array
|
|
511
|
+
*/
|
|
512
|
+
searchResultToArray(result) {
|
|
513
|
+
if (!result || !Array.isArray(result)) return [];
|
|
514
|
+
return result;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Connect to IMAP server
|
|
518
|
+
*/
|
|
519
|
+
async connect() {
|
|
520
|
+
try {
|
|
521
|
+
this.debug("Connecting to IMAP server", { host: this.options.host });
|
|
522
|
+
this.client = this.createClient();
|
|
523
|
+
await this.client.connect();
|
|
524
|
+
this.connected = true;
|
|
525
|
+
this.debug("IMAP connection established");
|
|
526
|
+
} catch (error) {
|
|
527
|
+
this.connected = false;
|
|
528
|
+
throw this.mapIMAPError(error);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Disconnect from IMAP server
|
|
533
|
+
*/
|
|
534
|
+
async disconnect() {
|
|
535
|
+
if (this.client) {
|
|
536
|
+
await this.client.logout();
|
|
537
|
+
this.client = null;
|
|
538
|
+
this.connected = false;
|
|
539
|
+
this.currentFolder = null;
|
|
540
|
+
this.debug("IMAP connection closed");
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Fetch messages with filters
|
|
545
|
+
*/
|
|
546
|
+
async fetch(options) {
|
|
547
|
+
this.ensureConnected();
|
|
548
|
+
const folder = options?.folder || "INBOX";
|
|
549
|
+
await this.selectFolder(folder);
|
|
550
|
+
try {
|
|
551
|
+
const searchQuery = this.buildSearchQuery(options);
|
|
552
|
+
this.debug("Fetching messages", {
|
|
553
|
+
folder,
|
|
554
|
+
query: searchQuery
|
|
555
|
+
});
|
|
556
|
+
const searchResult = await this.client.search(searchQuery, { uid: true });
|
|
557
|
+
const uids = this.searchResultToArray(searchResult);
|
|
558
|
+
let targetUids = uids;
|
|
559
|
+
if (options?.offset || options?.limit) {
|
|
560
|
+
const start = options.offset || 0;
|
|
561
|
+
const end = options.limit ? start + options.limit : void 0;
|
|
562
|
+
targetUids = uids.slice(start, end);
|
|
563
|
+
}
|
|
564
|
+
if (targetUids.length === 0) return [];
|
|
565
|
+
const messages = [];
|
|
566
|
+
for await (const msg of this.client.fetch(targetUids, {
|
|
567
|
+
source: true,
|
|
568
|
+
flags: true,
|
|
569
|
+
uid: true,
|
|
570
|
+
envelope: true,
|
|
571
|
+
bodyStructure: true
|
|
572
|
+
})) try {
|
|
573
|
+
if (!msg.source) {
|
|
574
|
+
this.debug("Message has no source", { uid: msg.uid });
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
const parsed = await simpleParser(msg.source);
|
|
578
|
+
const email = this.parseMessage(parsed, msg);
|
|
579
|
+
messages.push(email);
|
|
580
|
+
if (options?.markSeen) await this.client.messageFlagsAdd(msg.uid, ["\\Seen"], { uid: true });
|
|
581
|
+
} catch (parseError) {
|
|
582
|
+
this.debug("Failed to parse message", {
|
|
583
|
+
uid: msg.uid,
|
|
584
|
+
parseError
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
return messages;
|
|
588
|
+
} catch (error) {
|
|
589
|
+
throw this.mapIMAPError(error);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Get a specific message by ID
|
|
594
|
+
*/
|
|
595
|
+
async getMessage(messageId) {
|
|
596
|
+
this.ensureConnected();
|
|
597
|
+
try {
|
|
598
|
+
const searchResult = await this.client.search({ header: ["message-id", messageId] }, { uid: true });
|
|
599
|
+
const uids = this.searchResultToArray(searchResult);
|
|
600
|
+
if (uids.length === 0) throw new MessageNotFoundError(messageId, "imap");
|
|
601
|
+
const messages = [];
|
|
602
|
+
for await (const msg of this.client.fetch(uids[0], {
|
|
603
|
+
source: true,
|
|
604
|
+
flags: true,
|
|
605
|
+
uid: true
|
|
606
|
+
})) {
|
|
607
|
+
if (!msg.source) continue;
|
|
608
|
+
const parsed = await simpleParser(msg.source);
|
|
609
|
+
messages.push(this.parseMessage(parsed, msg));
|
|
610
|
+
}
|
|
611
|
+
if (messages.length === 0) throw new MessageNotFoundError(messageId, "imap");
|
|
612
|
+
return messages[0];
|
|
613
|
+
} catch (error) {
|
|
614
|
+
if (error instanceof EmailError) throw error;
|
|
615
|
+
throw this.mapIMAPError(error);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* List all folders
|
|
620
|
+
*/
|
|
621
|
+
async listFolders() {
|
|
622
|
+
this.ensureConnected();
|
|
623
|
+
try {
|
|
624
|
+
const list = await this.client?.list();
|
|
625
|
+
if (!list) return [];
|
|
626
|
+
return list.map((folder) => ({
|
|
627
|
+
name: folder.name,
|
|
628
|
+
path: folder.path,
|
|
629
|
+
delimiter: folder.delimiter,
|
|
630
|
+
specialUse: folder.specialUse,
|
|
631
|
+
subscribed: folder.subscribed
|
|
632
|
+
}));
|
|
633
|
+
} catch (error) {
|
|
634
|
+
throw this.mapIMAPError(error);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Select a folder
|
|
639
|
+
*/
|
|
640
|
+
async selectFolder(name) {
|
|
641
|
+
this.ensureConnected();
|
|
642
|
+
try {
|
|
643
|
+
const mailbox = await this.client?.mailboxOpen(name);
|
|
644
|
+
this.currentFolder = name;
|
|
645
|
+
if (!mailbox) throw new FolderNotFoundError(name, "imap");
|
|
646
|
+
return {
|
|
647
|
+
name,
|
|
648
|
+
exists: Number(mailbox.exists),
|
|
649
|
+
recent: 0,
|
|
650
|
+
unseen: 0,
|
|
651
|
+
uidValidity: Number(mailbox.uidValidity),
|
|
652
|
+
uidNext: Number(mailbox.uidNext),
|
|
653
|
+
flags: Array.from(mailbox.flags || []),
|
|
654
|
+
permanentFlags: Array.from(mailbox.permanentFlags || [])
|
|
655
|
+
};
|
|
656
|
+
} catch (error) {
|
|
657
|
+
if (error instanceof Error && error.message.toLowerCase().includes("does not exist")) throw new FolderNotFoundError(name, "imap");
|
|
658
|
+
throw this.mapIMAPError(error);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Create a new folder
|
|
663
|
+
*/
|
|
664
|
+
async createFolder(name) {
|
|
665
|
+
this.ensureConnected();
|
|
666
|
+
try {
|
|
667
|
+
await this.client?.mailboxCreate(name);
|
|
668
|
+
this.debug("Folder created", { name });
|
|
669
|
+
} catch (error) {
|
|
670
|
+
if (error instanceof Error && error.message.toLowerCase().includes("already exists")) throw new FolderExistsError(name, "imap");
|
|
671
|
+
throw this.mapIMAPError(error);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Delete a folder
|
|
676
|
+
*/
|
|
677
|
+
async deleteFolder(name) {
|
|
678
|
+
this.ensureConnected();
|
|
679
|
+
try {
|
|
680
|
+
await this.client?.mailboxDelete(name);
|
|
681
|
+
this.debug("Folder deleted", { name });
|
|
682
|
+
} catch (error) {
|
|
683
|
+
if (error instanceof Error && error.message.toLowerCase().includes("does not exist")) throw new FolderNotFoundError(name, "imap");
|
|
684
|
+
throw this.mapIMAPError(error);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Mark message(s) as read
|
|
689
|
+
*/
|
|
690
|
+
async markRead(messageId) {
|
|
691
|
+
this.ensureConnected();
|
|
692
|
+
const ids = Array.isArray(messageId) ? messageId : [messageId];
|
|
693
|
+
try {
|
|
694
|
+
for (const id of ids) {
|
|
695
|
+
const searchResult = await this.client?.search({ header: ["message-id", id] }, { uid: true });
|
|
696
|
+
const uids = this.searchResultToArray(searchResult);
|
|
697
|
+
if (uids.length > 0) await this.client?.messageFlagsAdd(uids[0], ["\\Seen"], { uid: true });
|
|
698
|
+
}
|
|
699
|
+
} catch (error) {
|
|
700
|
+
throw this.mapIMAPError(error);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Mark message(s) as unread
|
|
705
|
+
*/
|
|
706
|
+
async markUnread(messageId) {
|
|
707
|
+
this.ensureConnected();
|
|
708
|
+
const ids = Array.isArray(messageId) ? messageId : [messageId];
|
|
709
|
+
try {
|
|
710
|
+
for (const id of ids) {
|
|
711
|
+
const searchResult = await this.client?.search({ header: ["message-id", id] }, { uid: true });
|
|
712
|
+
const uids = this.searchResultToArray(searchResult);
|
|
713
|
+
if (uids.length > 0) await this.client?.messageFlagsRemove(uids[0], ["\\Seen"], { uid: true });
|
|
714
|
+
}
|
|
715
|
+
} catch (error) {
|
|
716
|
+
throw this.mapIMAPError(error);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Move message(s) to another folder
|
|
721
|
+
*/
|
|
722
|
+
async move(messageId, folder) {
|
|
723
|
+
this.ensureConnected();
|
|
724
|
+
const ids = Array.isArray(messageId) ? messageId : [messageId];
|
|
725
|
+
try {
|
|
726
|
+
for (const id of ids) {
|
|
727
|
+
const searchResult = await this.client?.search({ header: ["message-id", id] }, { uid: true });
|
|
728
|
+
const uids = this.searchResultToArray(searchResult);
|
|
729
|
+
if (uids.length > 0) await this.client?.messageMove(uids[0], folder, { uid: true });
|
|
730
|
+
}
|
|
731
|
+
} catch (error) {
|
|
732
|
+
throw this.mapIMAPError(error);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Copy message(s) to another folder
|
|
737
|
+
*/
|
|
738
|
+
async copy(messageId, folder) {
|
|
739
|
+
this.ensureConnected();
|
|
740
|
+
const ids = Array.isArray(messageId) ? messageId : [messageId];
|
|
741
|
+
try {
|
|
742
|
+
for (const id of ids) {
|
|
743
|
+
const searchResult = await this.client?.search({ header: ["message-id", id] }, { uid: true });
|
|
744
|
+
const uids = this.searchResultToArray(searchResult);
|
|
745
|
+
if (uids.length > 0) await this.client?.messageCopy(uids[0], folder, { uid: true });
|
|
746
|
+
}
|
|
747
|
+
} catch (error) {
|
|
748
|
+
throw this.mapIMAPError(error);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Delete message(s)
|
|
753
|
+
*/
|
|
754
|
+
async delete(messageId) {
|
|
755
|
+
this.ensureConnected();
|
|
756
|
+
const ids = Array.isArray(messageId) ? messageId : [messageId];
|
|
757
|
+
try {
|
|
758
|
+
for (const id of ids) {
|
|
759
|
+
const searchResult = await this.client?.search({ header: ["message-id", id] }, { uid: true });
|
|
760
|
+
const uids = this.searchResultToArray(searchResult);
|
|
761
|
+
if (uids.length > 0) await this.client?.messageFlagsAdd(uids[0], ["\\Deleted"], { uid: true });
|
|
762
|
+
}
|
|
763
|
+
} catch (error) {
|
|
764
|
+
throw this.mapIMAPError(error);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Search messages
|
|
769
|
+
*/
|
|
770
|
+
async search(criteria) {
|
|
771
|
+
this.ensureConnected();
|
|
772
|
+
try {
|
|
773
|
+
const query = this.buildSearchCriteria(criteria);
|
|
774
|
+
const searchResult = await this.client.search(query, { uid: true });
|
|
775
|
+
const uids = this.searchResultToArray(searchResult);
|
|
776
|
+
if (uids.length === 0) return [];
|
|
777
|
+
const messages = [];
|
|
778
|
+
for await (const msg of this.client.fetch(uids, {
|
|
779
|
+
source: true,
|
|
780
|
+
flags: true,
|
|
781
|
+
uid: true
|
|
782
|
+
})) {
|
|
783
|
+
if (!msg.source) continue;
|
|
784
|
+
const parsed = await simpleParser(msg.source);
|
|
785
|
+
messages.push(this.parseMessage(parsed, msg));
|
|
786
|
+
}
|
|
787
|
+
return messages;
|
|
788
|
+
} catch (error) {
|
|
789
|
+
throw this.mapIMAPError(error);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Get adapter capabilities
|
|
794
|
+
*/
|
|
795
|
+
async getCapabilities() {
|
|
796
|
+
return {
|
|
797
|
+
send: false,
|
|
798
|
+
receive: true,
|
|
799
|
+
folders: true,
|
|
800
|
+
search: true,
|
|
801
|
+
markRead: true,
|
|
802
|
+
move: true,
|
|
803
|
+
delete: true,
|
|
804
|
+
threads: false,
|
|
805
|
+
oauth: this.isOAuth2()
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Check if using OAuth2 authentication
|
|
810
|
+
*/
|
|
811
|
+
isOAuth2() {
|
|
812
|
+
return this.options.auth !== void 0 && "type" in this.options.auth && this.options.auth.type === "OAuth2";
|
|
813
|
+
}
|
|
814
|
+
async send(_message, _options) {
|
|
815
|
+
throw new EmailError("IMAP does not support sending messages. Use SMTP adapter.", "UNSUPPORTED_OPERATION", "imap");
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Ensure client is connected
|
|
819
|
+
*/
|
|
820
|
+
ensureConnected() {
|
|
821
|
+
if (!this.client || !this.connected) throw new ConnectionError("Not connected to IMAP server. Call connect() first.", "imap");
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Build IMAP search query from FetchOptions
|
|
825
|
+
*/
|
|
826
|
+
buildSearchQuery(options) {
|
|
827
|
+
const query = {};
|
|
828
|
+
if (options?.unreadOnly) query.unseen = true;
|
|
829
|
+
if (options?.since) query.since = options.since;
|
|
830
|
+
if (options?.before) query.before = options.before;
|
|
831
|
+
if (Object.keys(query).length === 0) query.all = true;
|
|
832
|
+
return query;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Build IMAP search criteria from SearchCriteria
|
|
836
|
+
*/
|
|
837
|
+
buildSearchCriteria(criteria) {
|
|
838
|
+
const query = {};
|
|
839
|
+
if (criteria.from) query.from = criteria.from;
|
|
840
|
+
if (criteria.to) query.to = criteria.to;
|
|
841
|
+
if (criteria.subject) query.subject = criteria.subject;
|
|
842
|
+
if (criteria.body) query.body = criteria.body;
|
|
843
|
+
if (criteria.since) query.since = criteria.since;
|
|
844
|
+
if (criteria.before) query.before = criteria.before;
|
|
845
|
+
if (criteria.unread) query.unseen = true;
|
|
846
|
+
if (criteria.flagged) query.flagged = true;
|
|
847
|
+
if (criteria.answered) query.answered = true;
|
|
848
|
+
if (criteria.draft) query.draft = true;
|
|
849
|
+
if (criteria.deleted) query.deleted = true;
|
|
850
|
+
if (criteria.larger) query.larger = criteria.larger;
|
|
851
|
+
if (criteria.smaller) query.smaller = criteria.smaller;
|
|
852
|
+
if (criteria.header) query.header = Object.entries(criteria.header).map(([key, value]) => [key, value]);
|
|
853
|
+
if (Object.keys(query).length === 0) query.all = true;
|
|
854
|
+
return query;
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Parse mailparser output to EmailMessage
|
|
858
|
+
*/
|
|
859
|
+
parseMessage(parsed, msg) {
|
|
860
|
+
const extractAddresses = (addressObj) => {
|
|
861
|
+
if (!addressObj) return [];
|
|
862
|
+
return (Array.isArray(addressObj) ? addressObj : [addressObj]).flatMap((obj) => Array.isArray(obj.value) ? obj.value : [obj.value]).map((addr) => ({
|
|
863
|
+
address: addr.address || "",
|
|
864
|
+
name: addr.name
|
|
865
|
+
}));
|
|
866
|
+
};
|
|
867
|
+
const fromAddresses = extractAddresses(parsed.from);
|
|
868
|
+
const toAddresses = extractAddresses(parsed.to);
|
|
869
|
+
const ccAddresses = extractAddresses(parsed.cc);
|
|
870
|
+
const bccAddresses = extractAddresses(parsed.bcc);
|
|
871
|
+
const replyToAddresses = extractAddresses(parsed.replyTo);
|
|
872
|
+
return {
|
|
873
|
+
id: String(msg.uid),
|
|
874
|
+
messageId: parsed.messageId || void 0,
|
|
875
|
+
from: fromAddresses[0] || {
|
|
876
|
+
address: "",
|
|
877
|
+
name: void 0
|
|
878
|
+
},
|
|
879
|
+
to: toAddresses,
|
|
880
|
+
cc: ccAddresses.length > 0 ? ccAddresses : void 0,
|
|
881
|
+
bcc: bccAddresses.length > 0 ? bccAddresses : void 0,
|
|
882
|
+
replyTo: replyToAddresses[0],
|
|
883
|
+
subject: parsed.subject || "",
|
|
884
|
+
date: parsed.date,
|
|
885
|
+
text: parsed.text,
|
|
886
|
+
html: parsed.html ? String(parsed.html) : void 0,
|
|
887
|
+
attachments: parsed.attachments?.map((att) => ({
|
|
888
|
+
filename: att.filename,
|
|
889
|
+
contentType: att.contentType,
|
|
890
|
+
size: att.size,
|
|
891
|
+
content: att.content,
|
|
892
|
+
contentId: att.contentId,
|
|
893
|
+
contentDisposition: att.contentDisposition
|
|
894
|
+
})),
|
|
895
|
+
flags: msg.flags ? Array.from(msg.flags) : void 0,
|
|
896
|
+
inReplyTo: parsed.inReplyTo,
|
|
897
|
+
references: Array.isArray(parsed.references) ? parsed.references : parsed.references ? [parsed.references] : void 0,
|
|
898
|
+
headers: parsed.headers ? Object.fromEntries(Array.from(parsed.headers.entries()).map(([key, value]) => [key, Array.isArray(value) ? value : String(value)])) : void 0
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Map ImapFlow errors to standard error types
|
|
903
|
+
*/
|
|
904
|
+
mapIMAPError(error) {
|
|
905
|
+
if (error instanceof EmailError) return error;
|
|
906
|
+
if (error instanceof Error) {
|
|
907
|
+
const message = error.message.toLowerCase();
|
|
908
|
+
if (message.includes("authentication") || message.includes("auth") || message.includes("login") || message.includes("invalid credentials")) return new AuthenticationError(error.message, "imap", error);
|
|
909
|
+
if (message.includes("timeout") || message.includes("etimedout")) return new TimeoutError(error.message, "imap", error);
|
|
910
|
+
if (message.includes("econnrefused") || message.includes("enotfound") || message.includes("connection") || message.includes("ehostunreach") || message.includes("network")) return new ConnectionError(error.message, "imap", error);
|
|
911
|
+
return new EmailError(error.message, "IMAP_ERROR", "imap", error);
|
|
912
|
+
}
|
|
913
|
+
return new EmailError(String(error), "UNKNOWN_ERROR", "imap");
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
//#endregion
|
|
917
|
+
//#region src/adapters/pop3.ts
|
|
918
|
+
/**
|
|
919
|
+
* POP3 adapter for receiving email
|
|
920
|
+
*/
|
|
921
|
+
var pop3_exports = /* @__PURE__ */ __exportAll({ POP3Adapter: () => POP3Adapter });
|
|
922
|
+
/**
|
|
923
|
+
* POP3 adapter implementation
|
|
924
|
+
*
|
|
925
|
+
* POP3 is a simple protocol for retrieving email. It does not support:
|
|
926
|
+
* - Folders (POP3 has no folder concept)
|
|
927
|
+
* - Marking messages as read/unread
|
|
928
|
+
* - Moving or copying messages
|
|
929
|
+
* - Server-side search
|
|
930
|
+
*
|
|
931
|
+
* By default, POP3 deletes messages from the server after retrieval.
|
|
932
|
+
* Use leaveOnServer: true to keep messages on the server.
|
|
933
|
+
*/
|
|
934
|
+
var POP3Adapter = class extends BaseEmailClient {
|
|
935
|
+
client = null;
|
|
936
|
+
options;
|
|
937
|
+
messageCache = /* @__PURE__ */ new Map();
|
|
938
|
+
constructor(options) {
|
|
939
|
+
super({
|
|
940
|
+
type: "pop3",
|
|
941
|
+
debug: options.debug
|
|
942
|
+
});
|
|
943
|
+
this.options = options;
|
|
944
|
+
}
|
|
945
|
+
async connect() {
|
|
946
|
+
try {
|
|
947
|
+
this.client = new Pop3Command({
|
|
948
|
+
user: this.options.auth.user,
|
|
949
|
+
password: this.options.auth.pass,
|
|
950
|
+
host: this.options.host,
|
|
951
|
+
port: this.options.port,
|
|
952
|
+
tls: this.options.secure ?? this.options.port === 995,
|
|
953
|
+
timeout: this.options.connectionTimeout,
|
|
954
|
+
tlsOptions: this.options.tls
|
|
955
|
+
});
|
|
956
|
+
await this.client.connect();
|
|
957
|
+
this.connected = true;
|
|
958
|
+
this.debug("Connected to POP3 server");
|
|
959
|
+
} catch (error) {
|
|
960
|
+
throw this.mapPOP3Error(error);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
async disconnect() {
|
|
964
|
+
if (!this.client) return;
|
|
965
|
+
try {
|
|
966
|
+
await this.client.QUIT();
|
|
967
|
+
this.client = null;
|
|
968
|
+
this.connected = false;
|
|
969
|
+
this.messageCache.clear();
|
|
970
|
+
this.debug("Disconnected from POP3 server");
|
|
971
|
+
} catch (error) {
|
|
972
|
+
this.client = null;
|
|
973
|
+
this.connected = false;
|
|
974
|
+
this.messageCache.clear();
|
|
975
|
+
throw this.mapPOP3Error(error);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
async fetch(options) {
|
|
979
|
+
this.ensureConnected();
|
|
980
|
+
try {
|
|
981
|
+
const uidlResponse = await this.client?.UIDL();
|
|
982
|
+
if (!uidlResponse || !uidlResponse[0]) return [];
|
|
983
|
+
const uidList = this.parseUidlResponse(Array.isArray(uidlResponse[0]) ? uidlResponse[0].join("\n") : uidlResponse[0]);
|
|
984
|
+
if (uidList.length === 0) return [];
|
|
985
|
+
this.messageCache.clear();
|
|
986
|
+
for (const { msgNum, uid } of uidList) this.messageCache.set(msgNum, uid);
|
|
987
|
+
let messageNums = uidList.map((item) => item.msgNum);
|
|
988
|
+
if (options?.offset) messageNums = messageNums.slice(options.offset);
|
|
989
|
+
if (options?.limit) messageNums = messageNums.slice(0, options.limit);
|
|
990
|
+
const messages = [];
|
|
991
|
+
for (const msgNum of messageNums) try {
|
|
992
|
+
const message = await this.fetchMessage(msgNum);
|
|
993
|
+
if (this.shouldIncludeMessage(message, options)) {
|
|
994
|
+
messages.push(message);
|
|
995
|
+
if (!this.options.leaveOnServer) await this.deleteMessageByNum(msgNum);
|
|
996
|
+
}
|
|
997
|
+
} catch (error) {
|
|
998
|
+
this.logger.error(`Failed to fetch message ${msgNum}:`, { error: error instanceof Error ? error.message : String(error) });
|
|
999
|
+
}
|
|
1000
|
+
return messages;
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
throw this.mapPOP3Error(error);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
async getMessage(messageId) {
|
|
1006
|
+
this.ensureConnected();
|
|
1007
|
+
try {
|
|
1008
|
+
let msgNum = null;
|
|
1009
|
+
for (const [num, uid] of this.messageCache.entries()) if (uid === messageId) {
|
|
1010
|
+
msgNum = num;
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
if (!msgNum) {
|
|
1014
|
+
const uidlResponse = await this.client?.UIDL();
|
|
1015
|
+
if (!uidlResponse || !uidlResponse[0]) throw new MessageNotFoundError(messageId, "pop3");
|
|
1016
|
+
const uidList = this.parseUidlResponse(Array.isArray(uidlResponse[0]) ? uidlResponse[0].join("\n") : uidlResponse[0]);
|
|
1017
|
+
this.messageCache.clear();
|
|
1018
|
+
for (const { msgNum: num, uid } of uidList) {
|
|
1019
|
+
this.messageCache.set(num, uid);
|
|
1020
|
+
if (uid === messageId) msgNum = num;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
if (!msgNum) throw new MessageNotFoundError(messageId, "pop3");
|
|
1024
|
+
return await this.fetchMessage(msgNum);
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
if (error instanceof MessageNotFoundError) throw error;
|
|
1027
|
+
throw this.mapPOP3Error(error);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
async delete(messageId) {
|
|
1031
|
+
this.ensureConnected();
|
|
1032
|
+
const ids = this.normalizeMessageIds(messageId);
|
|
1033
|
+
for (const id of ids) try {
|
|
1034
|
+
let msgNum = null;
|
|
1035
|
+
for (const [num, uid] of this.messageCache.entries()) if (uid === id) {
|
|
1036
|
+
msgNum = num;
|
|
1037
|
+
break;
|
|
1038
|
+
}
|
|
1039
|
+
if (!msgNum) {
|
|
1040
|
+
const uidlResponse = await this.client?.UIDL();
|
|
1041
|
+
if (!uidlResponse || !uidlResponse[0]) throw new MessageNotFoundError(id, "pop3");
|
|
1042
|
+
const uidList = this.parseUidlResponse(Array.isArray(uidlResponse[0]) ? uidlResponse[0].join("\n") : uidlResponse[0]);
|
|
1043
|
+
for (const { msgNum: num, uid } of uidList) if (uid === id) {
|
|
1044
|
+
msgNum = num;
|
|
1045
|
+
break;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
if (!msgNum) throw new MessageNotFoundError(id, "pop3");
|
|
1049
|
+
await this.deleteMessageByNum(msgNum);
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
throw this.mapPOP3Error(error);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
async send(_message, _options) {
|
|
1055
|
+
throw new EmailError("POP3 does not support sending email. Use SMTP instead.", "UNSUPPORTED_OPERATION", "pop3");
|
|
1056
|
+
}
|
|
1057
|
+
async listFolders() {
|
|
1058
|
+
throw new EmailError("POP3 does not support folders", "UNSUPPORTED_OPERATION", "pop3");
|
|
1059
|
+
}
|
|
1060
|
+
async selectFolder(_name) {
|
|
1061
|
+
throw new EmailError("POP3 does not support folders", "UNSUPPORTED_OPERATION", "pop3");
|
|
1062
|
+
}
|
|
1063
|
+
async createFolder(_name) {
|
|
1064
|
+
throw new EmailError("POP3 does not support folders", "UNSUPPORTED_OPERATION", "pop3");
|
|
1065
|
+
}
|
|
1066
|
+
async deleteFolder(_name) {
|
|
1067
|
+
throw new EmailError("POP3 does not support folders", "UNSUPPORTED_OPERATION", "pop3");
|
|
1068
|
+
}
|
|
1069
|
+
async markRead(_messageId) {
|
|
1070
|
+
throw new EmailError("POP3 does not support marking messages as read", "UNSUPPORTED_OPERATION", "pop3");
|
|
1071
|
+
}
|
|
1072
|
+
async markUnread(_messageId) {
|
|
1073
|
+
throw new EmailError("POP3 does not support marking messages as unread", "UNSUPPORTED_OPERATION", "pop3");
|
|
1074
|
+
}
|
|
1075
|
+
async move(_messageId, _folder) {
|
|
1076
|
+
throw new EmailError("POP3 does not support moving messages", "UNSUPPORTED_OPERATION", "pop3");
|
|
1077
|
+
}
|
|
1078
|
+
async copy(_messageId, _folder) {
|
|
1079
|
+
throw new EmailError("POP3 does not support copying messages", "UNSUPPORTED_OPERATION", "pop3");
|
|
1080
|
+
}
|
|
1081
|
+
async search(_criteria) {
|
|
1082
|
+
throw new EmailError("POP3 does not support server-side search. Use fetch() with filters instead.", "UNSUPPORTED_OPERATION", "pop3");
|
|
1083
|
+
}
|
|
1084
|
+
async getCapabilities() {
|
|
1085
|
+
return {
|
|
1086
|
+
send: false,
|
|
1087
|
+
receive: true,
|
|
1088
|
+
folders: false,
|
|
1089
|
+
search: false,
|
|
1090
|
+
markRead: false,
|
|
1091
|
+
move: false,
|
|
1092
|
+
delete: true,
|
|
1093
|
+
threads: false,
|
|
1094
|
+
oauth: false
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
getAdapter() {
|
|
1098
|
+
return "pop3";
|
|
1099
|
+
}
|
|
1100
|
+
ensureConnected() {
|
|
1101
|
+
if (!this.connected || !this.client) throw new ConnectionError("Not connected to POP3 server. Call connect() first.", "pop3");
|
|
1102
|
+
}
|
|
1103
|
+
async fetchMessage(msgNum) {
|
|
1104
|
+
try {
|
|
1105
|
+
const response = await this.client?.RETR(Number(msgNum));
|
|
1106
|
+
if (!response || !response[0]) throw new Error(`Failed to retrieve message ${msgNum}`);
|
|
1107
|
+
const messageData = response[0];
|
|
1108
|
+
const parsed = await simpleParser(messageData);
|
|
1109
|
+
const uid = this.messageCache.get(msgNum);
|
|
1110
|
+
const extractAddresses = (addressObj) => {
|
|
1111
|
+
if (!addressObj) return [];
|
|
1112
|
+
return (Array.isArray(addressObj) ? addressObj : [addressObj]).flatMap((obj) => Array.isArray(obj.value) ? obj.value : [obj.value]).map((addr) => ({
|
|
1113
|
+
address: addr.address || "",
|
|
1114
|
+
name: addr.name
|
|
1115
|
+
}));
|
|
1116
|
+
};
|
|
1117
|
+
const fromAddresses = extractAddresses(parsed.from);
|
|
1118
|
+
const toAddresses = extractAddresses(parsed.to);
|
|
1119
|
+
const ccAddresses = extractAddresses(parsed.cc);
|
|
1120
|
+
const bccAddresses = extractAddresses(parsed.bcc);
|
|
1121
|
+
const replyToAddresses = extractAddresses(parsed.replyTo);
|
|
1122
|
+
return {
|
|
1123
|
+
id: uid || msgNum,
|
|
1124
|
+
messageId: parsed.messageId || uid || msgNum,
|
|
1125
|
+
from: fromAddresses[0] || {
|
|
1126
|
+
address: "",
|
|
1127
|
+
name: void 0
|
|
1128
|
+
},
|
|
1129
|
+
to: toAddresses,
|
|
1130
|
+
cc: ccAddresses.length > 0 ? ccAddresses : void 0,
|
|
1131
|
+
bcc: bccAddresses.length > 0 ? bccAddresses : void 0,
|
|
1132
|
+
replyTo: replyToAddresses[0],
|
|
1133
|
+
subject: parsed.subject || "",
|
|
1134
|
+
date: parsed.date,
|
|
1135
|
+
text: parsed.text,
|
|
1136
|
+
html: parsed.html ? parsed.html.toString() : void 0,
|
|
1137
|
+
attachments: parsed.attachments?.map((att) => ({
|
|
1138
|
+
filename: att.filename,
|
|
1139
|
+
contentType: att.contentType,
|
|
1140
|
+
size: att.size,
|
|
1141
|
+
content: att.content,
|
|
1142
|
+
contentId: att.contentId,
|
|
1143
|
+
contentDisposition: att.contentDisposition
|
|
1144
|
+
})),
|
|
1145
|
+
headers: parsed.headers,
|
|
1146
|
+
size: messageData.length,
|
|
1147
|
+
raw: messageData
|
|
1148
|
+
};
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
throw this.mapPOP3Error(error);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
async deleteMessageByNum(msgNum) {
|
|
1154
|
+
try {
|
|
1155
|
+
await this.client?.command(`DELE ${msgNum}`);
|
|
1156
|
+
this.messageCache.delete(msgNum);
|
|
1157
|
+
this.debug(`Deleted message ${msgNum}`);
|
|
1158
|
+
} catch (error) {
|
|
1159
|
+
throw this.mapPOP3Error(error);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
parseUidlResponse(response) {
|
|
1163
|
+
const lines = response.split("\n");
|
|
1164
|
+
const result = [];
|
|
1165
|
+
for (const line of lines) {
|
|
1166
|
+
const trimmed = line.trim();
|
|
1167
|
+
if (!trimmed || trimmed === "." || trimmed.startsWith("+OK")) continue;
|
|
1168
|
+
const parts = trimmed.split(/\s+/);
|
|
1169
|
+
if (parts.length >= 2) result.push({
|
|
1170
|
+
msgNum: parts[0],
|
|
1171
|
+
uid: parts[1]
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
return result;
|
|
1175
|
+
}
|
|
1176
|
+
shouldIncludeMessage(message, options) {
|
|
1177
|
+
if (options?.since && message.date) {
|
|
1178
|
+
if (message.date < options.since) return false;
|
|
1179
|
+
}
|
|
1180
|
+
if (options?.before && message.date) {
|
|
1181
|
+
if (message.date >= options.before) return false;
|
|
1182
|
+
}
|
|
1183
|
+
return true;
|
|
1184
|
+
}
|
|
1185
|
+
mapPOP3Error(error) {
|
|
1186
|
+
if (error instanceof EmailError) return error;
|
|
1187
|
+
if (error instanceof Error) {
|
|
1188
|
+
const message = error.message.toLowerCase();
|
|
1189
|
+
const errorObj = error;
|
|
1190
|
+
if (message.includes("timeout") || errorObj.eventName === "timeout" || errorObj.code === "ETIMEDOUT") return new TimeoutError(error.message, "pop3", error);
|
|
1191
|
+
if (message.includes("connect") || message.includes("econnrefused") || message.includes("enotfound") || message.includes("ehostunreach") || errorObj.eventName === "error" || errorObj.eventName === "close" || errorObj.code === "ECONNREFUSED" || errorObj.code === "ENOTFOUND") return new ConnectionError(error.message, "pop3", error);
|
|
1192
|
+
if (message.includes("auth") || message.includes("login") || message.includes("password") || message.includes("user") || message.includes("-err")) return new AuthenticationError(error.message, "pop3", error);
|
|
1193
|
+
return new EmailError(error.message, "POP3_ERROR", "pop3", error);
|
|
1194
|
+
}
|
|
1195
|
+
return new EmailError(String(error), "POP3_ERROR", "pop3");
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
//#endregion
|
|
1199
|
+
//#region src/adapters/smtp.ts
|
|
1200
|
+
var smtp_exports = /* @__PURE__ */ __exportAll({ SMTPAdapter: () => SMTPAdapter });
|
|
1201
|
+
/**
|
|
1202
|
+
* SMTP adapter for sending email via SMTP protocol
|
|
1203
|
+
*
|
|
1204
|
+
* Uses Nodemailer for robust SMTP operations including:
|
|
1205
|
+
* - Plain text and HTML email
|
|
1206
|
+
* - Attachments (files and inline images)
|
|
1207
|
+
* - Multiple recipients (To, CC, BCC)
|
|
1208
|
+
* - Connection pooling
|
|
1209
|
+
* - OAuth2 authentication
|
|
1210
|
+
* - TLS/SSL support
|
|
1211
|
+
*/
|
|
1212
|
+
var SMTPAdapter = class extends BaseEmailClient {
|
|
1213
|
+
transporter;
|
|
1214
|
+
options;
|
|
1215
|
+
constructor(options) {
|
|
1216
|
+
super({
|
|
1217
|
+
type: "smtp",
|
|
1218
|
+
debug: options.debug
|
|
1219
|
+
});
|
|
1220
|
+
this.options = options;
|
|
1221
|
+
this.transporter = this.createTransporter();
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Create Nodemailer transporter with configuration
|
|
1225
|
+
*/
|
|
1226
|
+
createTransporter() {
|
|
1227
|
+
const config = {
|
|
1228
|
+
host: this.options.host,
|
|
1229
|
+
port: this.options.port,
|
|
1230
|
+
secure: this.options.secure ?? false,
|
|
1231
|
+
auth: this.options.auth,
|
|
1232
|
+
tls: this.options.tls,
|
|
1233
|
+
connectionTimeout: this.options.connectionTimeout,
|
|
1234
|
+
greetingTimeout: this.options.greetingTimeout,
|
|
1235
|
+
socketTimeout: this.options.socketTimeout,
|
|
1236
|
+
pool: this.options.pool,
|
|
1237
|
+
maxConnections: this.options.maxConnections,
|
|
1238
|
+
maxMessages: this.options.maxMessages,
|
|
1239
|
+
debug: this.options.debug
|
|
1240
|
+
};
|
|
1241
|
+
return nodemailer.createTransport(config);
|
|
1242
|
+
}
|
|
1243
|
+
getAdapter() {
|
|
1244
|
+
return "smtp";
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Send an email message
|
|
1248
|
+
*/
|
|
1249
|
+
async send(message, options) {
|
|
1250
|
+
this.validateMessage(message);
|
|
1251
|
+
try {
|
|
1252
|
+
const mailOptions = {
|
|
1253
|
+
from: this.formatEmailAddress(message.from),
|
|
1254
|
+
to: message.to.map((addr) => this.formatEmailAddress(addr)),
|
|
1255
|
+
cc: message.cc?.map((addr) => this.formatEmailAddress(addr)),
|
|
1256
|
+
bcc: message.bcc?.map((addr) => this.formatEmailAddress(addr)),
|
|
1257
|
+
subject: message.subject,
|
|
1258
|
+
text: message.text,
|
|
1259
|
+
html: message.html,
|
|
1260
|
+
replyTo: message.replyTo ? this.formatEmailAddress(message.replyTo) : void 0,
|
|
1261
|
+
inReplyTo: message.inReplyTo,
|
|
1262
|
+
references: message.references,
|
|
1263
|
+
attachments: message.attachments?.map((att) => ({
|
|
1264
|
+
filename: att.filename,
|
|
1265
|
+
content: att.content,
|
|
1266
|
+
path: att.path,
|
|
1267
|
+
contentType: att.contentType,
|
|
1268
|
+
cid: att.contentId,
|
|
1269
|
+
contentDisposition: att.contentDisposition
|
|
1270
|
+
})),
|
|
1271
|
+
headers: message.headers,
|
|
1272
|
+
messageId: message.messageId || options?.messageId,
|
|
1273
|
+
date: message.date || options?.date,
|
|
1274
|
+
encoding: options?.encoding,
|
|
1275
|
+
textEncoding: options?.textEncoding,
|
|
1276
|
+
envelope: options?.envelope,
|
|
1277
|
+
priority: options?.priority,
|
|
1278
|
+
dsn: options?.dsn
|
|
1279
|
+
};
|
|
1280
|
+
this.debug("Sending email", {
|
|
1281
|
+
to: mailOptions.to,
|
|
1282
|
+
subject: message.subject
|
|
1283
|
+
});
|
|
1284
|
+
const sendInfo = await this.transporter.sendMail(mailOptions);
|
|
1285
|
+
return {
|
|
1286
|
+
messageId: sendInfo.messageId,
|
|
1287
|
+
accepted: sendInfo.accepted,
|
|
1288
|
+
rejected: sendInfo.rejected,
|
|
1289
|
+
response: sendInfo.response
|
|
1290
|
+
};
|
|
1291
|
+
} catch (error) {
|
|
1292
|
+
throw this.mapSMTPError(error);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Format email address for Nodemailer
|
|
1297
|
+
*/
|
|
1298
|
+
formatEmailAddress(addr) {
|
|
1299
|
+
if (addr.name) return `"${addr.name.replace(/"/g, "\\\"")}" <${addr.address}>`;
|
|
1300
|
+
return addr.address;
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Map Nodemailer/SMTP errors to standard error types
|
|
1304
|
+
*/
|
|
1305
|
+
mapSMTPError(error) {
|
|
1306
|
+
if (error instanceof EmailError) return error;
|
|
1307
|
+
if (error instanceof Error) {
|
|
1308
|
+
const message = error.message.toLowerCase();
|
|
1309
|
+
if (message.includes("authentication") || message.includes("invalid login") || message.includes("535")) return new AuthenticationError(error.message, "smtp", error);
|
|
1310
|
+
if (message.includes("timeout") || message.includes("etimedout")) return new TimeoutError(error.message, "smtp", error);
|
|
1311
|
+
if (message.includes("econnrefused") || message.includes("enotfound") || message.includes("connection") || message.includes("ehostunreach")) return new ConnectionError(error.message, "smtp", error);
|
|
1312
|
+
if ("accepted" in error && "rejected" in error) {
|
|
1313
|
+
const errorWithRecipients = error;
|
|
1314
|
+
return new SendError(error.message, errorWithRecipients.accepted || [], errorWithRecipients.rejected || [], "smtp", error);
|
|
1315
|
+
}
|
|
1316
|
+
return new EmailError(error.message, "SMTP_ERROR", "smtp", error);
|
|
1317
|
+
}
|
|
1318
|
+
return new EmailError(String(error), "UNKNOWN_ERROR", "smtp");
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Connect to SMTP server (verify connection)
|
|
1322
|
+
*/
|
|
1323
|
+
async connect() {
|
|
1324
|
+
try {
|
|
1325
|
+
this.debug("Verifying SMTP connection", { host: this.options.host });
|
|
1326
|
+
await this.transporter.verify();
|
|
1327
|
+
this.connected = true;
|
|
1328
|
+
this.debug("SMTP connection verified");
|
|
1329
|
+
} catch (error) {
|
|
1330
|
+
this.connected = false;
|
|
1331
|
+
throw this.mapSMTPError(error);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Disconnect from SMTP server
|
|
1336
|
+
*/
|
|
1337
|
+
async disconnect() {
|
|
1338
|
+
this.transporter.close();
|
|
1339
|
+
this.connected = false;
|
|
1340
|
+
this.debug("SMTP connection closed");
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1343
|
+
* Get adapter capabilities
|
|
1344
|
+
*/
|
|
1345
|
+
async getCapabilities() {
|
|
1346
|
+
return {
|
|
1347
|
+
send: true,
|
|
1348
|
+
receive: false,
|
|
1349
|
+
folders: false,
|
|
1350
|
+
search: false,
|
|
1351
|
+
markRead: false,
|
|
1352
|
+
move: false,
|
|
1353
|
+
delete: false,
|
|
1354
|
+
threads: false,
|
|
1355
|
+
oauth: this.isOAuth2()
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Check if using OAuth2 authentication
|
|
1360
|
+
*/
|
|
1361
|
+
isOAuth2() {
|
|
1362
|
+
return this.options.auth !== void 0 && "type" in this.options.auth && this.options.auth.type === "OAuth2";
|
|
1363
|
+
}
|
|
1364
|
+
async fetch(_options) {
|
|
1365
|
+
throw new EmailError("SMTP does not support receiving messages. Use IMAP or POP3 adapter.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1366
|
+
}
|
|
1367
|
+
async getMessage(_messageId) {
|
|
1368
|
+
throw new EmailError("SMTP does not support receiving messages. Use IMAP or POP3 adapter.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1369
|
+
}
|
|
1370
|
+
async listFolders() {
|
|
1371
|
+
throw new EmailError("SMTP does not support folder operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1372
|
+
}
|
|
1373
|
+
async selectFolder(_name) {
|
|
1374
|
+
throw new EmailError("SMTP does not support folder operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1375
|
+
}
|
|
1376
|
+
async createFolder(_name) {
|
|
1377
|
+
throw new EmailError("SMTP does not support folder operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1378
|
+
}
|
|
1379
|
+
async deleteFolder(_name) {
|
|
1380
|
+
throw new EmailError("SMTP does not support folder operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1381
|
+
}
|
|
1382
|
+
async markRead(_messageId) {
|
|
1383
|
+
throw new EmailError("SMTP does not support message operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1384
|
+
}
|
|
1385
|
+
async markUnread(_messageId) {
|
|
1386
|
+
throw new EmailError("SMTP does not support message operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1387
|
+
}
|
|
1388
|
+
async move(_messageId, _folder) {
|
|
1389
|
+
throw new EmailError("SMTP does not support message operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1390
|
+
}
|
|
1391
|
+
async copy(_messageId, _folder) {
|
|
1392
|
+
throw new EmailError("SMTP does not support message operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1393
|
+
}
|
|
1394
|
+
async delete(_messageId) {
|
|
1395
|
+
throw new EmailError("SMTP does not support message operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1396
|
+
}
|
|
1397
|
+
async search(_criteria) {
|
|
1398
|
+
throw new EmailError("SMTP does not support search operations.", "UNSUPPORTED_OPERATION", "smtp");
|
|
1399
|
+
}
|
|
1400
|
+
};
|
|
1401
|
+
//#endregion
|
|
1402
|
+
//#region src/shared/factory.ts
|
|
2026
1403
|
function isSMTPOptions(opts) {
|
|
2027
|
-
|
|
1404
|
+
return opts.type === "smtp";
|
|
2028
1405
|
}
|
|
2029
1406
|
function isIMAPOptions(opts) {
|
|
2030
|
-
|
|
1407
|
+
return opts.type === "imap";
|
|
2031
1408
|
}
|
|
2032
1409
|
function isPOP3Options(opts) {
|
|
2033
|
-
|
|
1410
|
+
return opts.type === "pop3";
|
|
2034
1411
|
}
|
|
2035
1412
|
function isGmailOptions(opts) {
|
|
2036
|
-
|
|
1413
|
+
return opts.type === "gmail";
|
|
2037
1414
|
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Create an email client adapter instance
|
|
1417
|
+
*
|
|
1418
|
+
* @param options - Configuration options for the email client adapter
|
|
1419
|
+
* @returns Promise resolving to an EmailClient instance
|
|
1420
|
+
*
|
|
1421
|
+
* @example
|
|
1422
|
+
* ```typescript
|
|
1423
|
+
* // SMTP adapter
|
|
1424
|
+
* const smtp = await getEmailClient({
|
|
1425
|
+
* type: 'smtp',
|
|
1426
|
+
* host: 'smtp.gmail.com',
|
|
1427
|
+
* port: 587,
|
|
1428
|
+
* auth: { user: 'user@gmail.com', pass: 'password' }
|
|
1429
|
+
* });
|
|
1430
|
+
*
|
|
1431
|
+
* // IMAP adapter
|
|
1432
|
+
* const imap = await getEmailClient({
|
|
1433
|
+
* type: 'imap',
|
|
1434
|
+
* host: 'imap.gmail.com',
|
|
1435
|
+
* port: 993,
|
|
1436
|
+
* secure: true,
|
|
1437
|
+
* auth: { user: 'user@gmail.com', pass: 'password' }
|
|
1438
|
+
* });
|
|
1439
|
+
*
|
|
1440
|
+
* // Gmail adapter
|
|
1441
|
+
* const gmail = await getEmailClient({
|
|
1442
|
+
* type: 'gmail',
|
|
1443
|
+
* auth: {
|
|
1444
|
+
* clientId: 'CLIENT_ID',
|
|
1445
|
+
* clientSecret: 'CLIENT_SECRET',
|
|
1446
|
+
* refreshToken: 'REFRESH_TOKEN'
|
|
1447
|
+
* }
|
|
1448
|
+
* });
|
|
1449
|
+
* ```
|
|
1450
|
+
*/
|
|
2038
1451
|
async function getEmailClient(options) {
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
`Unknown email client type: ${opts.type}`
|
|
2058
|
-
);
|
|
1452
|
+
const opts = await loadEnvironmentConfig(options);
|
|
1453
|
+
if (isSMTPOptions(opts)) {
|
|
1454
|
+
const { SMTPAdapter } = await Promise.resolve().then(() => smtp_exports);
|
|
1455
|
+
return new SMTPAdapter(opts);
|
|
1456
|
+
}
|
|
1457
|
+
if (isIMAPOptions(opts)) {
|
|
1458
|
+
const { IMAPAdapter } = await Promise.resolve().then(() => imap_exports);
|
|
1459
|
+
return new IMAPAdapter(opts);
|
|
1460
|
+
}
|
|
1461
|
+
if (isPOP3Options(opts)) {
|
|
1462
|
+
const { POP3Adapter } = await Promise.resolve().then(() => pop3_exports);
|
|
1463
|
+
return new POP3Adapter(opts);
|
|
1464
|
+
}
|
|
1465
|
+
if (isGmailOptions(opts)) {
|
|
1466
|
+
const { GmailAdapter } = await Promise.resolve().then(() => gmail_exports);
|
|
1467
|
+
return new GmailAdapter(opts);
|
|
1468
|
+
}
|
|
1469
|
+
throw new Error(`Unknown email client type: ${opts.type}`);
|
|
2059
1470
|
}
|
|
1471
|
+
/**
|
|
1472
|
+
* Load configuration from environment variables
|
|
1473
|
+
*
|
|
1474
|
+
* Environment variables follow the pattern: HAVE_EMAIL_*
|
|
1475
|
+
*
|
|
1476
|
+
* Common variables:
|
|
1477
|
+
* - HAVE_EMAIL_TYPE: Adapter type (smtp, imap, pop3, gmail)
|
|
1478
|
+
* - HAVE_EMAIL_HOST: Server host
|
|
1479
|
+
* - HAVE_EMAIL_PORT: Server port
|
|
1480
|
+
* - HAVE_EMAIL_SECURE: Use TLS/SSL (true/false)
|
|
1481
|
+
* - HAVE_EMAIL_USER: Username/email
|
|
1482
|
+
* - HAVE_EMAIL_PASSWORD: Password
|
|
1483
|
+
* - HAVE_EMAIL_DEBUG: Enable debug logging (true/false)
|
|
1484
|
+
*
|
|
1485
|
+
* SMTP-specific:
|
|
1486
|
+
* - HAVE_EMAIL_SMTP_HOST
|
|
1487
|
+
* - HAVE_EMAIL_SMTP_PORT
|
|
1488
|
+
* - HAVE_EMAIL_SMTP_SECURE
|
|
1489
|
+
*
|
|
1490
|
+
* IMAP-specific:
|
|
1491
|
+
* - HAVE_EMAIL_IMAP_HOST
|
|
1492
|
+
* - HAVE_EMAIL_IMAP_PORT
|
|
1493
|
+
* - HAVE_EMAIL_IMAP_SECURE
|
|
1494
|
+
*
|
|
1495
|
+
* Gmail-specific:
|
|
1496
|
+
* - HAVE_EMAIL_GMAIL_CLIENT_ID
|
|
1497
|
+
* - HAVE_EMAIL_GMAIL_CLIENT_SECRET
|
|
1498
|
+
* - HAVE_EMAIL_GMAIL_REFRESH_TOKEN
|
|
1499
|
+
*/
|
|
2060
1500
|
async function loadEnvironmentConfig(options) {
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
if (options.type === "imap") {
|
|
2071
|
-
return loadIMAPEnvironmentConfig(options);
|
|
2072
|
-
}
|
|
2073
|
-
if (options.type === "pop3") {
|
|
2074
|
-
return loadPOP3EnvironmentConfig(options);
|
|
2075
|
-
}
|
|
2076
|
-
if (options.type === "gmail") {
|
|
2077
|
-
return loadGmailEnvironmentConfig(options);
|
|
2078
|
-
}
|
|
2079
|
-
return options;
|
|
1501
|
+
if (!options.type && process.env.HAVE_EMAIL_TYPE) options = {
|
|
1502
|
+
...options,
|
|
1503
|
+
type: process.env.HAVE_EMAIL_TYPE
|
|
1504
|
+
};
|
|
1505
|
+
if (options.type === "smtp") return loadSMTPEnvironmentConfig(options);
|
|
1506
|
+
if (options.type === "imap") return loadIMAPEnvironmentConfig(options);
|
|
1507
|
+
if (options.type === "pop3") return loadPOP3EnvironmentConfig(options);
|
|
1508
|
+
if (options.type === "gmail") return loadGmailEnvironmentConfig(options);
|
|
1509
|
+
return options;
|
|
2080
1510
|
}
|
|
2081
1511
|
function loadSMTPEnvironmentConfig(options) {
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
},
|
|
2094
|
-
debug: options.debug ?? process.env.HAVE_EMAIL_DEBUG === "true"
|
|
2095
|
-
};
|
|
1512
|
+
return {
|
|
1513
|
+
...options,
|
|
1514
|
+
host: options.host || process.env.HAVE_EMAIL_SMTP_HOST || process.env.HAVE_EMAIL_HOST || "",
|
|
1515
|
+
port: options.port || Number.parseInt(process.env.HAVE_EMAIL_SMTP_PORT || process.env.HAVE_EMAIL_PORT || "587", 10),
|
|
1516
|
+
secure: options.secure ?? (process.env.HAVE_EMAIL_SMTP_SECURE || process.env.HAVE_EMAIL_SECURE) === "true",
|
|
1517
|
+
auth: options.auth || {
|
|
1518
|
+
user: process.env.HAVE_EMAIL_USER || process.env.HAVE_EMAIL_SMTP_USER,
|
|
1519
|
+
pass: process.env.HAVE_EMAIL_PASSWORD || process.env.HAVE_EMAIL_SMTP_PASSWORD
|
|
1520
|
+
},
|
|
1521
|
+
debug: options.debug ?? process.env.HAVE_EMAIL_DEBUG === "true"
|
|
1522
|
+
};
|
|
2096
1523
|
}
|
|
2097
1524
|
function loadIMAPEnvironmentConfig(options) {
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
},
|
|
2110
|
-
debug: options.debug ?? process.env.HAVE_EMAIL_DEBUG === "true"
|
|
2111
|
-
};
|
|
1525
|
+
return {
|
|
1526
|
+
...options,
|
|
1527
|
+
host: options.host || process.env.HAVE_EMAIL_IMAP_HOST || process.env.HAVE_EMAIL_HOST || "",
|
|
1528
|
+
port: options.port || Number.parseInt(process.env.HAVE_EMAIL_IMAP_PORT || process.env.HAVE_EMAIL_PORT || "993", 10),
|
|
1529
|
+
secure: options.secure ?? (process.env.HAVE_EMAIL_IMAP_SECURE || process.env.HAVE_EMAIL_SECURE) === "true",
|
|
1530
|
+
auth: options.auth || {
|
|
1531
|
+
user: process.env.HAVE_EMAIL_USER || process.env.HAVE_EMAIL_IMAP_USER,
|
|
1532
|
+
pass: process.env.HAVE_EMAIL_PASSWORD || process.env.HAVE_EMAIL_IMAP_PASSWORD
|
|
1533
|
+
},
|
|
1534
|
+
debug: options.debug ?? process.env.HAVE_EMAIL_DEBUG === "true"
|
|
1535
|
+
};
|
|
2112
1536
|
}
|
|
2113
1537
|
function loadPOP3EnvironmentConfig(options) {
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
},
|
|
2126
|
-
debug: options.debug ?? process.env.HAVE_EMAIL_DEBUG === "true"
|
|
2127
|
-
};
|
|
1538
|
+
return {
|
|
1539
|
+
...options,
|
|
1540
|
+
host: options.host || process.env.HAVE_EMAIL_POP3_HOST || process.env.HAVE_EMAIL_HOST || "",
|
|
1541
|
+
port: options.port || Number.parseInt(process.env.HAVE_EMAIL_POP3_PORT || process.env.HAVE_EMAIL_PORT || "995", 10),
|
|
1542
|
+
secure: options.secure ?? (process.env.HAVE_EMAIL_POP3_SECURE || process.env.HAVE_EMAIL_SECURE) === "true",
|
|
1543
|
+
auth: options.auth || {
|
|
1544
|
+
user: process.env.HAVE_EMAIL_USER || process.env.HAVE_EMAIL_POP3_USER,
|
|
1545
|
+
pass: process.env.HAVE_EMAIL_PASSWORD || process.env.HAVE_EMAIL_POP3_PASSWORD
|
|
1546
|
+
},
|
|
1547
|
+
debug: options.debug ?? process.env.HAVE_EMAIL_DEBUG === "true"
|
|
1548
|
+
};
|
|
2128
1549
|
}
|
|
2129
1550
|
function loadGmailEnvironmentConfig(options) {
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
1551
|
+
return {
|
|
1552
|
+
...options,
|
|
1553
|
+
auth: options.auth || {
|
|
1554
|
+
clientId: process.env.HAVE_EMAIL_GMAIL_CLIENT_ID || "",
|
|
1555
|
+
clientSecret: process.env.HAVE_EMAIL_GMAIL_CLIENT_SECRET || "",
|
|
1556
|
+
refreshToken: process.env.HAVE_EMAIL_GMAIL_REFRESH_TOKEN || "",
|
|
1557
|
+
accessToken: process.env.HAVE_EMAIL_GMAIL_ACCESS_TOKEN
|
|
1558
|
+
},
|
|
1559
|
+
userId: options.userId || process.env.HAVE_EMAIL_GMAIL_USER_ID || "me",
|
|
1560
|
+
debug: options.debug ?? process.env.HAVE_EMAIL_DEBUG === "true"
|
|
1561
|
+
};
|
|
2141
1562
|
}
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
BaseEmailClient,
|
|
2147
|
-
ConnectionError,
|
|
2148
|
-
EmailError,
|
|
2149
|
-
FolderExistsError,
|
|
2150
|
-
FolderNotFoundError,
|
|
2151
|
-
GmailAdapter,
|
|
2152
|
-
IMAPAdapter,
|
|
2153
|
-
InvalidMessageError,
|
|
2154
|
-
MessageNotFoundError,
|
|
2155
|
-
POP3Adapter,
|
|
2156
|
-
SMTPAdapter,
|
|
2157
|
-
SendError,
|
|
2158
|
-
TimeoutError,
|
|
2159
|
-
getEmailClient,
|
|
2160
|
-
isGmailOptions,
|
|
2161
|
-
isIMAPOptions,
|
|
2162
|
-
isPOP3Options,
|
|
2163
|
-
isSMTPOptions
|
|
2164
|
-
};
|
|
2165
|
-
//# sourceMappingURL=index.js.map
|
|
1563
|
+
//#endregion
|
|
1564
|
+
export { AttachmentError, AuthenticationError, AuthorizationError, BaseEmailClient, ConnectionError, EmailError, FolderExistsError, FolderNotFoundError, GmailAdapter, IMAPAdapter, InvalidMessageError, MessageNotFoundError, POP3Adapter, SMTPAdapter, SendError, TimeoutError, getEmailClient, isGmailOptions, isIMAPOptions, isPOP3Options, isSMTPOptions };
|
|
1565
|
+
|
|
1566
|
+
//# sourceMappingURL=index.js.map
|