nolimit-x 1.0.81 → 1.0.83
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/package.json +1 -1
- package/src/sender.js +23 -117
package/package.json
CHANGED
package/src/sender.js
CHANGED
|
@@ -488,130 +488,36 @@ async function send(options) {
|
|
|
488
488
|
let totalSent = 0;
|
|
489
489
|
|
|
490
490
|
if (allJobs.length > 0) {
|
|
491
|
-
|
|
492
|
-
|
|
491
|
+
// Assign SMTPs round-robin upfront
|
|
493
492
|
if (_smtpRotation && _smtpArr.length > 1) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const deadSmtps = new Set();
|
|
499
|
-
const rateLimited = new Set();
|
|
500
|
-
let healthyPool = [..._smtpArr];
|
|
501
|
-
let jobQueue = allJobs.map((job, idx) => ({ job, email: allEmails[idx] }));
|
|
502
|
-
const retryQueue = []; // failed jobs to retry through healthy SMTPs
|
|
503
|
-
|
|
504
|
-
while (jobQueue.length > 0 && healthyPool.length > 0) {
|
|
505
|
-
// Build one chunk: assign 1 job per healthy SMTP
|
|
506
|
-
const chunkSize = healthyPool.length;
|
|
507
|
-
const chunk = jobQueue.splice(0, chunkSize);
|
|
508
|
-
|
|
509
|
-
// Assign each job in the chunk to a different SMTP
|
|
510
|
-
for (let i = 0; i < chunk.length; i++) {
|
|
511
|
-
const smtp = healthyPool[i % healthyPool.length];
|
|
512
|
-
chunk[i].job.smtp = [smtp];
|
|
513
|
-
chunk[i].job.from = smtp.user;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// Send the chunk
|
|
517
|
-
const chunkJobs = chunk.map(c => c.job);
|
|
518
|
-
const results = await sendEmailViaRust(chunkJobs, useRawSmtp);
|
|
519
|
-
|
|
520
|
-
// Process results and track health
|
|
521
|
-
for (let i = 0; i < results.length; i++) {
|
|
522
|
-
const result = results[i];
|
|
523
|
-
const { job, email } = chunk[i];
|
|
524
|
-
const sender = job.from || job.from_email;
|
|
525
|
-
const smtpUser = job.smtp?.[0]?.user || '';
|
|
526
|
-
|
|
527
|
-
if (configManager.config.configurations.multiple_senders === true && sender) {
|
|
528
|
-
senderRanker.updateSenderSuccess(sender, result.success);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if (result.success) {
|
|
532
|
-
campaign.successfulSends++;
|
|
533
|
-
totalSent++;
|
|
534
|
-
try { senderIntel.recordSuccessfulSend(campaignId, sender, email, result); } catch (e) { }
|
|
535
|
-
} else {
|
|
536
|
-
const errMsg = (result.error || result.message || '').toLowerCase();
|
|
537
|
-
if (errMsg.includes('535') || errMsg.includes('authentication failed')) {
|
|
538
|
-
deadSmtps.add(smtpUser);
|
|
539
|
-
retryQueue.push({ job, email }); // re-queue for healthy SMTP
|
|
540
|
-
} else if (errMsg.includes('554') || errMsg.includes('limit') || errMsg.includes('smtp auth error limit')) {
|
|
541
|
-
rateLimited.add(smtpUser);
|
|
542
|
-
retryQueue.push({ job, email }); // re-queue for healthy SMTP
|
|
543
|
-
} else {
|
|
544
|
-
// Genuine failure (bad recipient, DNS, etc.) — don't retry
|
|
545
|
-
campaign.failedSends++;
|
|
546
|
-
try { senderIntel.recordFailedSend(campaignId, sender, email, result); } catch (e) { }
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
campaign.processedEmails++;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// Prune dead and rate-limited SMTPs from pool
|
|
553
|
-
const beforeCount = healthyPool.length;
|
|
554
|
-
healthyPool = healthyPool.filter(s => !deadSmtps.has(s.user) && !rateLimited.has(s.user));
|
|
555
|
-
|
|
556
|
-
if (healthyPool.length < beforeCount && healthyPool.length > 0) {
|
|
557
|
-
console.log(`${YELLOW}⚠ ${beforeCount - healthyPool.length} SMTP(s) removed · ${healthyPool.length} healthy remaining${RESET}`);
|
|
558
|
-
}
|
|
493
|
+
for (let i = 0; i < allJobs.length; i++) {
|
|
494
|
+
const smtp = _smtpArr[i % _smtpArr.length];
|
|
495
|
+
allJobs[i].smtp = [smtp];
|
|
496
|
+
allJobs[i].from = smtp.user;
|
|
559
497
|
}
|
|
498
|
+
}
|
|
560
499
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
for (let i = 0; i < retryQueue.length; i++) {
|
|
564
|
-
const smtp = healthyPool[i % healthyPool.length];
|
|
565
|
-
retryQueue[i].job.smtp = [smtp];
|
|
566
|
-
retryQueue[i].job.from = smtp.user;
|
|
567
|
-
}
|
|
568
|
-
const retryResults = await sendEmailViaRust(retryQueue.map(r => r.job), useRawSmtp);
|
|
569
|
-
for (let i = 0; i < retryResults.length; i++) {
|
|
570
|
-
const result = retryResults[i];
|
|
571
|
-
const { job, email } = retryQueue[i];
|
|
572
|
-
const sender = job.from || job.from_email;
|
|
573
|
-
if (result.success) {
|
|
574
|
-
campaign.successfulSends++;
|
|
575
|
-
totalSent++;
|
|
576
|
-
try { senderIntel.recordSuccessfulSend(campaignId, sender, email, result); } catch (e) { }
|
|
577
|
-
} else {
|
|
578
|
-
campaign.failedSends++;
|
|
579
|
-
try { senderIntel.recordFailedSend(campaignId, sender, email, result); } catch (e) { }
|
|
580
|
-
}
|
|
581
|
-
campaign.processedEmails++;
|
|
582
|
-
}
|
|
583
|
-
} else if (retryQueue.length > 0) {
|
|
584
|
-
// No healthy SMTPs left — mark all retries as failed
|
|
585
|
-
campaign.failedSends += retryQueue.length;
|
|
586
|
-
}
|
|
500
|
+
console.log('');
|
|
501
|
+
const results = await sendEmailViaRust(allJobs, useRawSmtp);
|
|
587
502
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
503
|
+
for (let i = 0; i < results.length; i++) {
|
|
504
|
+
const result = results[i];
|
|
505
|
+
const email = allEmails[i];
|
|
506
|
+
const sender = allJobs[i].from || allJobs[i].from_email;
|
|
592
507
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
for (let i = 0; i < results.length; i++) {
|
|
597
|
-
const result = results[i];
|
|
598
|
-
const email = allEmails[i];
|
|
599
|
-
const sender = allJobs[i].from || allJobs[i].from_email;
|
|
600
|
-
|
|
601
|
-
if (configManager.config.configurations.multiple_senders === true && sender) {
|
|
602
|
-
senderRanker.updateSenderSuccess(sender, result.success);
|
|
603
|
-
}
|
|
508
|
+
if (configManager.config.configurations.multiple_senders === true && sender) {
|
|
509
|
+
senderRanker.updateSenderSuccess(sender, result.success);
|
|
510
|
+
}
|
|
604
511
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
613
|
-
campaign.processedEmails++;
|
|
512
|
+
if (result.success) {
|
|
513
|
+
campaign.successfulSends++;
|
|
514
|
+
totalSent++;
|
|
515
|
+
try { senderIntel.recordSuccessfulSend(campaignId, sender, email, result); } catch (e) { }
|
|
516
|
+
} else {
|
|
517
|
+
campaign.failedSends++;
|
|
518
|
+
try { senderIntel.recordFailedSend(campaignId, sender, email, result); } catch (e) { }
|
|
614
519
|
}
|
|
520
|
+
campaign.processedEmails++;
|
|
615
521
|
}
|
|
616
522
|
}
|
|
617
523
|
// End campaign
|