nolimit-x 1.0.82 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/sender.js +23 -117
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nolimit-x",
3
- "version": "1.0.82",
3
+ "version": "1.0.83",
4
4
  "description": "Advanced email sender ",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
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
- console.log('');
492
-
491
+ // Assign SMTPs round-robin upfront
493
492
  if (_smtpRotation && _smtpArr.length > 1) {
494
- // ─── CHUNKED HEALTH-AWARE SENDING ───
495
- // Send in sub-batches (1 email per SMTP per chunk).
496
- // After each chunk, detect dead/rate-limited SMTPs and remove them.
497
- // Dead SMTPs waste at most 1 email instead of hundreds.
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
- // Retry queue: send failed emails through surviving healthy SMTPs
562
- if (retryQueue.length > 0 && healthyPool.length > 0) {
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
- // Any jobs left in queue (no healthy SMTPs broke the loop)
589
- if (jobQueue.length > 0) {
590
- campaign.failedSends += jobQueue.length;
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
- } else {
594
- // ─── SINGLE SMTP (no rotation) — send all at once ───
595
- const results = await sendEmailViaRust(allJobs, useRawSmtp);
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
- if (result.success) {
606
- campaign.successfulSends++;
607
- totalSent++;
608
- try { senderIntel.recordSuccessfulSend(campaignId, sender, email, result); } catch (e) { }
609
- } else {
610
- campaign.failedSends++;
611
- try { senderIntel.recordFailedSend(campaignId, sender, email, result); } catch (e) { }
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