@xuda.io/ai_module 1.1.4710 → 1.1.4712
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/index.mjs +697 -696
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -5533,6 +5533,7 @@ setTimeout(async () => {
|
|
|
5533
5533
|
// await init_studio_units();
|
|
5534
5534
|
let ret;
|
|
5535
5535
|
// ret = await is_spam_email(uid, 'dsgr8-2994400420@gigs.craigslist.org', 'To: You, From: Us - 70% Off Stickers & Labels Today Only');
|
|
5536
|
+
ret = await is_spam_email(uid, 'noreply@tm.openai.com', 'Please update your Plus payment method', account_profile_info);
|
|
5536
5537
|
// ret = await delete_depended_chats(uid);
|
|
5537
5538
|
// ret = await run_plugin(app_id, uid, '@xuda.io/xuda-library-plugin-studio-ai-app-builder', 'table_builder', { name: 'test2', prompt: 'build items table', save: true });
|
|
5538
5539
|
// ret = await run_plugin(app_id, uid, '@xuda.io/xuda-library-plugin-studio-ai-app-builder', 'folder_builder', { name: 'test', prompt: 'build boaz folder', save: true, parentId: 'programs' });
|
|
@@ -10417,792 +10418,792 @@ PROVIDE DETAILED ANALYSIS WITH CONFIDENCE LEVELS.`,
|
|
|
10417
10418
|
}
|
|
10418
10419
|
};
|
|
10419
10420
|
|
|
10420
|
-
export const detect_email_type = async function (uid, name, email, account_profile_info, email_body = '', email_subject = '') {
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10429
|
-
|
|
10430
|
-
|
|
10431
|
-
|
|
10432
|
-
|
|
10433
|
-
|
|
10434
|
-
function enhanceEmailDetection(data, name, email, emailBody, emailSubject) {
|
|
10435
|
-
// Run additional local analysis
|
|
10436
|
-
const localAnalysis = analyzeEmailLocally(emailBody, emailSubject, email, name);
|
|
10437
|
-
|
|
10438
|
-
// Combine AI analysis with local analysis
|
|
10439
|
-
const combinedData = {
|
|
10440
|
-
...data,
|
|
10441
|
-
// Override with local analysis if confidence is high
|
|
10442
|
-
spam_confidence: Math.max(data.spam_confidence, localAnalysis.spamScore),
|
|
10443
|
-
phishing_risk: localAnalysis.phishingScore > 70 ? 'high' : data.phishing_risk,
|
|
10444
|
-
|
|
10445
|
-
// Add local analysis results
|
|
10446
|
-
local_analysis: localAnalysis,
|
|
10447
|
-
|
|
10448
|
-
// Enhance sender analysis
|
|
10449
|
-
sender_analysis: analyzeSender(email, name, emailBody),
|
|
10450
|
-
|
|
10451
|
-
// Content statistics
|
|
10452
|
-
content_stats: {
|
|
10453
|
-
word_count: (emailBody.match(/\S+/g) || []).length,
|
|
10454
|
-
sentence_count: (emailBody.match(/[.!?]+/g) || []).length,
|
|
10455
|
-
link_count: (emailBody.match(/https?:\/\/[^\s]+/g) || []).length,
|
|
10456
|
-
uppercase_ratio: calculateUppercaseRatio(emailBody),
|
|
10457
|
-
exclamation_count: (emailBody.match(/!/g) || []).length,
|
|
10458
|
-
dollar_sign_count: (emailBody.match(/\$/g) || []).length,
|
|
10459
|
-
phone_patterns: (emailBody.match(/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g) || []).length,
|
|
10460
|
-
},
|
|
10461
|
-
|
|
10462
|
-
// Behavioral patterns
|
|
10463
|
-
behavioral_patterns: detectBehavioralPatterns(emailBody, emailSubject),
|
|
10464
|
-
|
|
10465
|
-
// Domain reputation
|
|
10466
|
-
domain_reputation: assessDomainReputation(email),
|
|
10467
|
-
|
|
10468
|
-
// Add comprehensive risk assessment
|
|
10469
|
-
comprehensive_risk_score: calculateComprehensiveRisk(data, localAnalysis),
|
|
10470
|
-
|
|
10471
|
-
// Filter rules that matched
|
|
10472
|
-
matched_filters: detectMatchedFilters(emailBody, emailSubject, email, name),
|
|
10473
|
-
|
|
10474
|
-
// Timeline analysis
|
|
10475
|
-
temporal_analysis: {
|
|
10476
|
-
is_time_sensitive: detectTimeSensitivity(emailBody),
|
|
10477
|
-
has_expiry: detectExpiryDate(emailBody),
|
|
10478
|
-
is_follow_up: detectFollowUpPattern(emailBody, emailSubject),
|
|
10479
|
-
},
|
|
10480
|
-
|
|
10481
|
-
// Relationship context
|
|
10482
|
-
relationship_context: analyzeRelationshipContext(emailBody, emailSubject, name),
|
|
10483
|
-
|
|
10484
|
-
// Update timestamp
|
|
10485
|
-
analysis_timestamp: new Date().toISOString(),
|
|
10486
|
-
content_length: emailBody.length,
|
|
10487
|
-
};
|
|
10488
|
-
|
|
10489
|
-
// Calculate final classification confidence
|
|
10490
|
-
combinedData.final_confidence = calculateFinalConfidence(combinedData);
|
|
10491
|
-
|
|
10492
|
-
// Generate detailed explanation
|
|
10493
|
-
combinedData.explanation = generateExplanation(combinedData);
|
|
10494
|
-
|
|
10495
|
-
// Add compliance flags
|
|
10496
|
-
combinedData.compliance_flags = checkCompliance(emailBody, emailSubject);
|
|
10497
|
-
|
|
10498
|
-
return combinedData;
|
|
10499
|
-
}
|
|
10500
|
-
|
|
10501
|
-
function analyzeEmailLocally(body, subject, email, name) {
|
|
10502
|
-
const text = (subject + ' ' + body).toLowerCase();
|
|
10503
|
-
let spamScore = 0;
|
|
10504
|
-
let phishingScore = 0;
|
|
10505
|
-
let promotionalScore = 0;
|
|
10506
|
-
let transactionalScore = 0;
|
|
10507
|
-
|
|
10508
|
-
// SPAM indicators
|
|
10509
|
-
const spamKeywords = [
|
|
10510
|
-
'congratulations',
|
|
10511
|
-
'winner',
|
|
10512
|
-
'prize',
|
|
10513
|
-
'lottery',
|
|
10514
|
-
'free',
|
|
10515
|
-
'guaranteed',
|
|
10516
|
-
'risk-free',
|
|
10517
|
-
'act now',
|
|
10518
|
-
'limited time',
|
|
10519
|
-
'urgent',
|
|
10520
|
-
'important',
|
|
10521
|
-
'attention',
|
|
10522
|
-
'alert',
|
|
10523
|
-
'click here',
|
|
10524
|
-
'buy now',
|
|
10525
|
-
'order now',
|
|
10526
|
-
'discount',
|
|
10527
|
-
'save big',
|
|
10528
|
-
'cheap',
|
|
10529
|
-
'viagra',
|
|
10530
|
-
'cialis',
|
|
10531
|
-
'pharmacy',
|
|
10532
|
-
'prescription',
|
|
10533
|
-
'enlarge',
|
|
10534
|
-
'weight loss',
|
|
10535
|
-
'nigerian',
|
|
10536
|
-
'prince',
|
|
10537
|
-
'inheritance',
|
|
10538
|
-
'unclaimed',
|
|
10539
|
-
'bank account',
|
|
10540
|
-
'password',
|
|
10541
|
-
'account suspended',
|
|
10542
|
-
'verify',
|
|
10543
|
-
'security alert',
|
|
10544
|
-
'dear friend',
|
|
10545
|
-
'dear customer',
|
|
10546
|
-
'dear account holder',
|
|
10547
|
-
];
|
|
10548
|
-
|
|
10549
|
-
spamKeywords.forEach((keyword) => {
|
|
10550
|
-
if (text.includes(keyword)) spamScore += 2;
|
|
10551
|
-
});
|
|
10552
|
-
|
|
10553
|
-
// Phishing indicators
|
|
10554
|
-
const phishingPatterns = [/login\s*(?:here|now)/i, /verify\s*(?:your|my)\s*account/i, /password\s*(?:reset|expired|change)/i, /suspended\s*account/i, /unauthorized\s*activity/i, /security\s*breach/i, /update\s*(?:your|my)\s*information/i, /confirm\s*(?:your|my)\s*identity/i];
|
|
10555
|
-
|
|
10556
|
-
phishingPatterns.forEach((pattern) => {
|
|
10557
|
-
if (pattern.test(text)) phishingScore += 15;
|
|
10558
|
-
});
|
|
10559
|
-
|
|
10560
|
-
// Promotional indicators
|
|
10561
|
-
const promotionalKeywords = ['newsletter', 'subscribe', 'unsubscribe', 'marketing', 'promotion', 'sale', 'offer', 'deal', 'coupon', 'voucher', 'discount code', 'new product', 'announcement', 'launch', 'event', 'webinar', 'limited offer', 'exclusive', 'special offer', 'members only'];
|
|
10562
|
-
|
|
10563
|
-
promotionalKeywords.forEach((keyword) => {
|
|
10564
|
-
if (text.includes(keyword)) promotionalScore += 3;
|
|
10565
|
-
});
|
|
10566
|
-
|
|
10567
|
-
// Transactional indicators
|
|
10568
|
-
const transactionalKeywords = ['order', 'invoice', 'receipt', 'payment', 'booking', 'reservation', 'confirmation', 'shipping', 'delivery', 'tracking', 'shipment', 'appointment', 'meeting', 'reminder', 'bill', 'statement', 'account', 'statement', 'balance', 'transaction'];
|
|
10569
|
-
|
|
10570
|
-
transactionalKeywords.forEach((keyword) => {
|
|
10571
|
-
if (text.includes(keyword)) transactionalScore += 3;
|
|
10572
|
-
});
|
|
10573
|
-
|
|
10574
|
-
// Link analysis
|
|
10575
|
-
const links = body.match(/https?:\/\/[^\s]+/g) || [];
|
|
10576
|
-
const suspiciousDomains = ['bit.ly', 'tinyurl', 'shorte.st', 'adf.ly', 'goo.gl'];
|
|
10577
|
-
|
|
10578
|
-
links.forEach((link) => {
|
|
10579
|
-
if (suspiciousDomains.some((domain) => link.includes(domain))) {
|
|
10580
|
-
spamScore += 10;
|
|
10581
|
-
phishingScore += 10;
|
|
10582
|
-
}
|
|
10583
|
-
});
|
|
10584
|
-
|
|
10585
|
-
// Grammar/spelling analysis (simple)
|
|
10586
|
-
const misspellings = body.match(/\b(?:recieve|seperate|definately|occured|tomm?orrow)\b/gi) || [];
|
|
10587
|
-
spamScore += misspellings.length * 2;
|
|
10588
|
-
|
|
10589
|
-
// Urgency analysis
|
|
10590
|
-
const urgencyWords = ['urgent', 'immediately', 'asap', 'right now', 'today only'];
|
|
10591
|
-
let urgencyCount = 0;
|
|
10592
|
-
urgencyWords.forEach((word) => {
|
|
10593
|
-
if (text.includes(word)) urgencyCount++;
|
|
10594
|
-
});
|
|
10595
|
-
spamScore += urgencyCount * 5;
|
|
10596
|
-
|
|
10597
|
-
// Personalization check
|
|
10598
|
-
const hasName = name && body.toLowerCase().includes(name.toLowerCase().split(' ')[0]);
|
|
10599
|
-
const personalPronouns = ['you', 'your', 'yours'];
|
|
10600
|
-
let personalCount = 0;
|
|
10601
|
-
personalPronouns.forEach((pronoun) => {
|
|
10602
|
-
const regex = new RegExp(`\\b${pronoun}\\b`, 'gi');
|
|
10603
|
-
personalCount += (body.match(regex) || []).length;
|
|
10604
|
-
});
|
|
10605
|
-
|
|
10606
|
-
const personalizationScore = hasName ? 30 : Math.min(personalCount * 2, 20);
|
|
10607
|
-
|
|
10608
|
-
return {
|
|
10609
|
-
spamScore: Math.min(spamScore, 100),
|
|
10610
|
-
phishingScore: Math.min(phishingScore, 100),
|
|
10611
|
-
promotionalScore: Math.min(promotionalScore, 100),
|
|
10612
|
-
transactionalScore: Math.min(transactionalScore, 100),
|
|
10613
|
-
personalizationScore,
|
|
10614
|
-
linkCount: links.length,
|
|
10615
|
-
hasUnsubscribe: text.includes('unsubscribe') || text.includes('opt-out'),
|
|
10616
|
-
hasPhone: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/.test(body),
|
|
10617
|
-
hasAddress: /\b\d+\s+[\w\s]+(?:street|st|avenue|ave|road|rd|boulevard|blvd|way)\b/i.test(body),
|
|
10618
|
-
urgencyCount,
|
|
10619
|
-
misspellingCount: misspellings.length,
|
|
10620
|
-
};
|
|
10621
|
-
}
|
|
10622
|
-
|
|
10623
|
-
function analyzeSender(email, name, body) {
|
|
10624
|
-
const domain = email.split('@')[1] || '';
|
|
10625
|
-
const localPart = email.split('@')[0] || '';
|
|
10626
|
-
|
|
10627
|
-
return {
|
|
10628
|
-
email: email,
|
|
10629
|
-
domain: domain,
|
|
10630
|
-
local_part: localPart,
|
|
10631
|
-
is_public_domain: isPublicEmailDomain(domain),
|
|
10632
|
-
is_generic_sender: isGenericSender(localPart, name),
|
|
10633
|
-
domain_age_indicator: assessDomainAge(domain),
|
|
10634
|
-
sender_consistency: checkSenderConsistency(name, email, body),
|
|
10635
|
-
};
|
|
10636
|
-
}
|
|
10637
|
-
|
|
10638
|
-
function isPublicEmailDomain(domain) {
|
|
10639
|
-
const publicDomains = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'aol.com', 'icloud.com', 'protonmail.com', 'zoho.com', 'yandex.com'];
|
|
10640
|
-
return publicDomains.includes(domain.toLowerCase());
|
|
10641
|
-
}
|
|
10642
|
-
|
|
10643
|
-
function isGenericSender(localPart, name) {
|
|
10644
|
-
const genericSenders = ['info', 'support', 'sales', 'contact', 'hello', 'noreply', 'admin', 'newsletter', 'marketing', 'team', 'notifications'];
|
|
10645
|
-
|
|
10646
|
-
const localLower = localPart.toLowerCase();
|
|
10647
|
-
const nameLower = name.toLowerCase();
|
|
10648
|
-
|
|
10649
|
-
return genericSenders.some((sender) => localLower.includes(sender) || nameLower.includes(sender));
|
|
10650
|
-
}
|
|
10651
|
-
|
|
10652
|
-
function assessDomainAge(domain) {
|
|
10653
|
-
// This is a simplified version - in production, you'd use a domain age API
|
|
10654
|
-
const newDomains = ['xyz', 'online', 'site', 'top', 'club', 'shop'];
|
|
10655
|
-
const tld = domain.split('.').pop() || '';
|
|
10656
|
-
|
|
10657
|
-
if (newDomains.includes(tld)) return 'likely_new';
|
|
10658
|
-
if (['com', 'org', 'net', 'edu', 'gov'].includes(tld)) return 'likely_established';
|
|
10659
|
-
return 'unknown';
|
|
10660
|
-
}
|
|
10421
|
+
// export const detect_email_type = async function (uid, name, email, account_profile_info, email_body = '', email_subject = '') {
|
|
10422
|
+
// // ========== HELPER FUNCTIONS ==========
|
|
10423
|
+
|
|
10424
|
+
// async function hashString(str) {
|
|
10425
|
+
// const encoder = new TextEncoder();
|
|
10426
|
+
// const data = encoder.encode(str);
|
|
10427
|
+
// const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
10428
|
+
// const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
10429
|
+
// return hashArray
|
|
10430
|
+
// .map((b) => b.toString(16).padStart(2, '0'))
|
|
10431
|
+
// .join('')
|
|
10432
|
+
// .substring(0, 16);
|
|
10433
|
+
// }
|
|
10661
10434
|
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10435
|
+
// function enhanceEmailDetection(data, name, email, emailBody, emailSubject) {
|
|
10436
|
+
// // Run additional local analysis
|
|
10437
|
+
// const localAnalysis = analyzeEmailLocally(emailBody, emailSubject, email, name);
|
|
10438
|
+
|
|
10439
|
+
// // Combine AI analysis with local analysis
|
|
10440
|
+
// const combinedData = {
|
|
10441
|
+
// ...data,
|
|
10442
|
+
// // Override with local analysis if confidence is high
|
|
10443
|
+
// spam_confidence: Math.max(data.spam_confidence, localAnalysis.spamScore),
|
|
10444
|
+
// phishing_risk: localAnalysis.phishingScore > 70 ? 'high' : data.phishing_risk,
|
|
10445
|
+
|
|
10446
|
+
// // Add local analysis results
|
|
10447
|
+
// local_analysis: localAnalysis,
|
|
10448
|
+
|
|
10449
|
+
// // Enhance sender analysis
|
|
10450
|
+
// sender_analysis: analyzeSender(email, name, emailBody),
|
|
10451
|
+
|
|
10452
|
+
// // Content statistics
|
|
10453
|
+
// content_stats: {
|
|
10454
|
+
// word_count: (emailBody.match(/\S+/g) || []).length,
|
|
10455
|
+
// sentence_count: (emailBody.match(/[.!?]+/g) || []).length,
|
|
10456
|
+
// link_count: (emailBody.match(/https?:\/\/[^\s]+/g) || []).length,
|
|
10457
|
+
// uppercase_ratio: calculateUppercaseRatio(emailBody),
|
|
10458
|
+
// exclamation_count: (emailBody.match(/!/g) || []).length,
|
|
10459
|
+
// dollar_sign_count: (emailBody.match(/\$/g) || []).length,
|
|
10460
|
+
// phone_patterns: (emailBody.match(/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g) || []).length,
|
|
10461
|
+
// },
|
|
10665
10462
|
|
|
10666
|
-
|
|
10667
|
-
|
|
10463
|
+
// // Behavioral patterns
|
|
10464
|
+
// behavioral_patterns: detectBehavioralPatterns(emailBody, emailSubject),
|
|
10668
10465
|
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
const firstName = nameParts[0] || '';
|
|
10672
|
-
const lastName = nameParts.slice(-1)[0] || '';
|
|
10466
|
+
// // Domain reputation
|
|
10467
|
+
// domain_reputation: assessDomainReputation(email),
|
|
10673
10468
|
|
|
10674
|
-
|
|
10469
|
+
// // Add comprehensive risk assessment
|
|
10470
|
+
// comprehensive_risk_score: calculateComprehensiveRisk(data, localAnalysis),
|
|
10675
10471
|
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
return {
|
|
10679
|
-
name_in_body: nameInBody,
|
|
10680
|
-
email_name_consistent: consistent,
|
|
10681
|
-
consistency_score: (nameInBody ? 40 : 0) + (consistent ? 60 : 0),
|
|
10682
|
-
};
|
|
10683
|
-
}
|
|
10472
|
+
// // Filter rules that matched
|
|
10473
|
+
// matched_filters: detectMatchedFilters(emailBody, emailSubject, email, name),
|
|
10684
10474
|
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10475
|
+
// // Timeline analysis
|
|
10476
|
+
// temporal_analysis: {
|
|
10477
|
+
// is_time_sensitive: detectTimeSensitivity(emailBody),
|
|
10478
|
+
// has_expiry: detectExpiryDate(emailBody),
|
|
10479
|
+
// is_follow_up: detectFollowUpPattern(emailBody, emailSubject),
|
|
10480
|
+
// },
|
|
10688
10481
|
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
}
|
|
10482
|
+
// // Relationship context
|
|
10483
|
+
// relationship_context: analyzeRelationshipContext(emailBody, emailSubject, name),
|
|
10692
10484
|
|
|
10693
|
-
|
|
10694
|
-
|
|
10695
|
-
|
|
10485
|
+
// // Update timestamp
|
|
10486
|
+
// analysis_timestamp: new Date().toISOString(),
|
|
10487
|
+
// content_length: emailBody.length,
|
|
10488
|
+
// };
|
|
10696
10489
|
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
}
|
|
10490
|
+
// // Calculate final classification confidence
|
|
10491
|
+
// combinedData.final_confidence = calculateFinalConfidence(combinedData);
|
|
10700
10492
|
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
}
|
|
10493
|
+
// // Generate detailed explanation
|
|
10494
|
+
// combinedData.explanation = generateExplanation(combinedData);
|
|
10704
10495
|
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
}
|
|
10496
|
+
// // Add compliance flags
|
|
10497
|
+
// combinedData.compliance_flags = checkCompliance(emailBody, emailSubject);
|
|
10708
10498
|
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
}
|
|
10499
|
+
// return combinedData;
|
|
10500
|
+
// }
|
|
10712
10501
|
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10502
|
+
// function analyzeEmailLocally(body, subject, email, name) {
|
|
10503
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10504
|
+
// let spamScore = 0;
|
|
10505
|
+
// let phishingScore = 0;
|
|
10506
|
+
// let promotionalScore = 0;
|
|
10507
|
+
// let transactionalScore = 0;
|
|
10508
|
+
|
|
10509
|
+
// // SPAM indicators
|
|
10510
|
+
// const spamKeywords = [
|
|
10511
|
+
// 'congratulations',
|
|
10512
|
+
// 'winner',
|
|
10513
|
+
// 'prize',
|
|
10514
|
+
// 'lottery',
|
|
10515
|
+
// 'free',
|
|
10516
|
+
// 'guaranteed',
|
|
10517
|
+
// 'risk-free',
|
|
10518
|
+
// 'act now',
|
|
10519
|
+
// 'limited time',
|
|
10520
|
+
// 'urgent',
|
|
10521
|
+
// 'important',
|
|
10522
|
+
// 'attention',
|
|
10523
|
+
// 'alert',
|
|
10524
|
+
// 'click here',
|
|
10525
|
+
// 'buy now',
|
|
10526
|
+
// 'order now',
|
|
10527
|
+
// 'discount',
|
|
10528
|
+
// 'save big',
|
|
10529
|
+
// 'cheap',
|
|
10530
|
+
// 'viagra',
|
|
10531
|
+
// 'cialis',
|
|
10532
|
+
// 'pharmacy',
|
|
10533
|
+
// 'prescription',
|
|
10534
|
+
// 'enlarge',
|
|
10535
|
+
// 'weight loss',
|
|
10536
|
+
// 'nigerian',
|
|
10537
|
+
// 'prince',
|
|
10538
|
+
// 'inheritance',
|
|
10539
|
+
// 'unclaimed',
|
|
10540
|
+
// 'bank account',
|
|
10541
|
+
// 'password',
|
|
10542
|
+
// 'account suspended',
|
|
10543
|
+
// 'verify',
|
|
10544
|
+
// 'security alert',
|
|
10545
|
+
// 'dear friend',
|
|
10546
|
+
// 'dear customer',
|
|
10547
|
+
// 'dear account holder',
|
|
10548
|
+
// ];
|
|
10549
|
+
|
|
10550
|
+
// spamKeywords.forEach((keyword) => {
|
|
10551
|
+
// if (text.includes(keyword)) spamScore += 2;
|
|
10552
|
+
// });
|
|
10553
|
+
|
|
10554
|
+
// // Phishing indicators
|
|
10555
|
+
// const phishingPatterns = [/login\s*(?:here|now)/i, /verify\s*(?:your|my)\s*account/i, /password\s*(?:reset|expired|change)/i, /suspended\s*account/i, /unauthorized\s*activity/i, /security\s*breach/i, /update\s*(?:your|my)\s*information/i, /confirm\s*(?:your|my)\s*identity/i];
|
|
10556
|
+
|
|
10557
|
+
// phishingPatterns.forEach((pattern) => {
|
|
10558
|
+
// if (pattern.test(text)) phishingScore += 15;
|
|
10559
|
+
// });
|
|
10560
|
+
|
|
10561
|
+
// // Promotional indicators
|
|
10562
|
+
// const promotionalKeywords = ['newsletter', 'subscribe', 'unsubscribe', 'marketing', 'promotion', 'sale', 'offer', 'deal', 'coupon', 'voucher', 'discount code', 'new product', 'announcement', 'launch', 'event', 'webinar', 'limited offer', 'exclusive', 'special offer', 'members only'];
|
|
10563
|
+
|
|
10564
|
+
// promotionalKeywords.forEach((keyword) => {
|
|
10565
|
+
// if (text.includes(keyword)) promotionalScore += 3;
|
|
10566
|
+
// });
|
|
10567
|
+
|
|
10568
|
+
// // Transactional indicators
|
|
10569
|
+
// const transactionalKeywords = ['order', 'invoice', 'receipt', 'payment', 'booking', 'reservation', 'confirmation', 'shipping', 'delivery', 'tracking', 'shipment', 'appointment', 'meeting', 'reminder', 'bill', 'statement', 'account', 'statement', 'balance', 'transaction'];
|
|
10570
|
+
|
|
10571
|
+
// transactionalKeywords.forEach((keyword) => {
|
|
10572
|
+
// if (text.includes(keyword)) transactionalScore += 3;
|
|
10573
|
+
// });
|
|
10574
|
+
|
|
10575
|
+
// // Link analysis
|
|
10576
|
+
// const links = body.match(/https?:\/\/[^\s]+/g) || [];
|
|
10577
|
+
// const suspiciousDomains = ['bit.ly', 'tinyurl', 'shorte.st', 'adf.ly', 'goo.gl'];
|
|
10578
|
+
|
|
10579
|
+
// links.forEach((link) => {
|
|
10580
|
+
// if (suspiciousDomains.some((domain) => link.includes(domain))) {
|
|
10581
|
+
// spamScore += 10;
|
|
10582
|
+
// phishingScore += 10;
|
|
10583
|
+
// }
|
|
10584
|
+
// });
|
|
10585
|
+
|
|
10586
|
+
// // Grammar/spelling analysis (simple)
|
|
10587
|
+
// const misspellings = body.match(/\b(?:recieve|seperate|definately|occured|tomm?orrow)\b/gi) || [];
|
|
10588
|
+
// spamScore += misspellings.length * 2;
|
|
10589
|
+
|
|
10590
|
+
// // Urgency analysis
|
|
10591
|
+
// const urgencyWords = ['urgent', 'immediately', 'asap', 'right now', 'today only'];
|
|
10592
|
+
// let urgencyCount = 0;
|
|
10593
|
+
// urgencyWords.forEach((word) => {
|
|
10594
|
+
// if (text.includes(word)) urgencyCount++;
|
|
10595
|
+
// });
|
|
10596
|
+
// spamScore += urgencyCount * 5;
|
|
10597
|
+
|
|
10598
|
+
// // Personalization check
|
|
10599
|
+
// const hasName = name && body.toLowerCase().includes(name.toLowerCase().split(' ')[0]);
|
|
10600
|
+
// const personalPronouns = ['you', 'your', 'yours'];
|
|
10601
|
+
// let personalCount = 0;
|
|
10602
|
+
// personalPronouns.forEach((pronoun) => {
|
|
10603
|
+
// const regex = new RegExp(`\\b${pronoun}\\b`, 'gi');
|
|
10604
|
+
// personalCount += (body.match(regex) || []).length;
|
|
10605
|
+
// });
|
|
10606
|
+
|
|
10607
|
+
// const personalizationScore = hasName ? 30 : Math.min(personalCount * 2, 20);
|
|
10716
10608
|
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10609
|
+
// return {
|
|
10610
|
+
// spamScore: Math.min(spamScore, 100),
|
|
10611
|
+
// phishingScore: Math.min(phishingScore, 100),
|
|
10612
|
+
// promotionalScore: Math.min(promotionalScore, 100),
|
|
10613
|
+
// transactionalScore: Math.min(transactionalScore, 100),
|
|
10614
|
+
// personalizationScore,
|
|
10615
|
+
// linkCount: links.length,
|
|
10616
|
+
// hasUnsubscribe: text.includes('unsubscribe') || text.includes('opt-out'),
|
|
10617
|
+
// hasPhone: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/.test(body),
|
|
10618
|
+
// hasAddress: /\b\d+\s+[\w\s]+(?:street|st|avenue|ave|road|rd|boulevard|blvd|way)\b/i.test(body),
|
|
10619
|
+
// urgencyCount,
|
|
10620
|
+
// misspellingCount: misspellings.length,
|
|
10621
|
+
// };
|
|
10622
|
+
// }
|
|
10720
10623
|
|
|
10721
|
-
|
|
10722
|
-
|
|
10624
|
+
// function analyzeSender(email, name, body) {
|
|
10625
|
+
// const domain = email.split('@')[1] || '';
|
|
10626
|
+
// const localPart = email.split('@')[0] || '';
|
|
10723
10627
|
|
|
10724
|
-
|
|
10725
|
-
|
|
10628
|
+
// return {
|
|
10629
|
+
// email: email,
|
|
10630
|
+
// domain: domain,
|
|
10631
|
+
// local_part: localPart,
|
|
10632
|
+
// is_public_domain: isPublicEmailDomain(domain),
|
|
10633
|
+
// is_generic_sender: isGenericSender(localPart, name),
|
|
10634
|
+
// domain_age_indicator: assessDomainAge(domain),
|
|
10635
|
+
// sender_consistency: checkSenderConsistency(name, email, body),
|
|
10636
|
+
// };
|
|
10637
|
+
// }
|
|
10726
10638
|
|
|
10727
|
-
|
|
10728
|
-
|
|
10639
|
+
// function isPublicEmailDomain(domain) {
|
|
10640
|
+
// const publicDomains = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'aol.com', 'icloud.com', 'protonmail.com', 'zoho.com', 'yandex.com'];
|
|
10641
|
+
// return publicDomains.includes(domain.toLowerCase());
|
|
10642
|
+
// }
|
|
10729
10643
|
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
}
|
|
10644
|
+
// function isGenericSender(localPart, name) {
|
|
10645
|
+
// const genericSenders = ['info', 'support', 'sales', 'contact', 'hello', 'noreply', 'admin', 'newsletter', 'marketing', 'team', 'notifications'];
|
|
10733
10646
|
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
const tld = domain.split('.').pop() || '';
|
|
10647
|
+
// const localLower = localPart.toLowerCase();
|
|
10648
|
+
// const nameLower = name.toLowerCase();
|
|
10737
10649
|
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
}
|
|
10650
|
+
// return genericSenders.some((sender) => localLower.includes(sender) || nameLower.includes(sender));
|
|
10651
|
+
// }
|
|
10741
10652
|
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
}
|
|
10653
|
+
// function assessDomainAge(domain) {
|
|
10654
|
+
// // This is a simplified version - in production, you'd use a domain age API
|
|
10655
|
+
// const newDomains = ['xyz', 'online', 'site', 'top', 'club', 'shop'];
|
|
10656
|
+
// const tld = domain.split('.').pop() || '';
|
|
10747
10657
|
|
|
10748
|
-
|
|
10749
|
-
|
|
10658
|
+
// if (newDomains.includes(tld)) return 'likely_new';
|
|
10659
|
+
// if (['com', 'org', 'net', 'edu', 'gov'].includes(tld)) return 'likely_established';
|
|
10660
|
+
// return 'unknown';
|
|
10661
|
+
// }
|
|
10750
10662
|
|
|
10751
|
-
|
|
10752
|
-
|
|
10663
|
+
// function checkSenderConsistency(name, email, body) {
|
|
10664
|
+
// const emailName = email.split('@')[0].toLowerCase();
|
|
10665
|
+
// const bodyName = name.toLowerCase();
|
|
10753
10666
|
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
case 'spam':
|
|
10757
|
-
risk += 80;
|
|
10758
|
-
break;
|
|
10759
|
-
case 'promotional':
|
|
10760
|
-
risk += 30;
|
|
10761
|
-
break;
|
|
10762
|
-
case 'transactional':
|
|
10763
|
-
risk += 10;
|
|
10764
|
-
break;
|
|
10765
|
-
case 'personal':
|
|
10766
|
-
risk += 5;
|
|
10767
|
-
break;
|
|
10768
|
-
case 'business':
|
|
10769
|
-
risk += 15;
|
|
10770
|
-
break;
|
|
10771
|
-
}
|
|
10667
|
+
// // Check if name appears in body
|
|
10668
|
+
// const nameInBody = body.toLowerCase().includes(bodyName.split(' ')[0]);
|
|
10772
10669
|
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10670
|
+
// // Check email-name consistency patterns
|
|
10671
|
+
// const nameParts = bodyName.split(' ');
|
|
10672
|
+
// const firstName = nameParts[0] || '';
|
|
10673
|
+
// const lastName = nameParts.slice(-1)[0] || '';
|
|
10776
10674
|
|
|
10777
|
-
|
|
10778
|
-
switch (aiData.phishing_risk) {
|
|
10779
|
-
case 'critical':
|
|
10780
|
-
risk += 40;
|
|
10781
|
-
break;
|
|
10782
|
-
case 'high':
|
|
10783
|
-
risk += 30;
|
|
10784
|
-
break;
|
|
10785
|
-
case 'medium':
|
|
10786
|
-
risk += 15;
|
|
10787
|
-
break;
|
|
10788
|
-
case 'low':
|
|
10789
|
-
risk += 5;
|
|
10790
|
-
break;
|
|
10791
|
-
}
|
|
10675
|
+
// const patterns = [`${firstName}.${lastName}`, `${firstName}${lastName}`, `${firstName.charAt(0)}${lastName}`, `${firstName}`];
|
|
10792
10676
|
|
|
10793
|
-
|
|
10794
|
-
if (aiData.is_unsolicited) risk += 20;
|
|
10677
|
+
// const consistent = patterns.some((pattern) => emailName.includes(pattern.toLowerCase()));
|
|
10795
10678
|
|
|
10796
|
-
|
|
10797
|
-
|
|
10679
|
+
// return {
|
|
10680
|
+
// name_in_body: nameInBody,
|
|
10681
|
+
// email_name_consistent: consistent,
|
|
10682
|
+
// consistency_score: (nameInBody ? 40 : 0) + (consistent ? 60 : 0),
|
|
10683
|
+
// };
|
|
10684
|
+
// }
|
|
10798
10685
|
|
|
10799
|
-
|
|
10800
|
-
|
|
10686
|
+
// function calculateUppercaseRatio(text) {
|
|
10687
|
+
// const letters = text.replace(/[^a-zA-Z]/g, '');
|
|
10688
|
+
// if (letters.length === 0) return 0;
|
|
10801
10689
|
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10690
|
+
// const uppercase = letters.replace(/[^A-Z]/g, '');
|
|
10691
|
+
// return (uppercase.length / letters.length) * 100;
|
|
10692
|
+
// }
|
|
10805
10693
|
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
if (/(?:nigerian|prince|inheritance|unclaimed)/i.test(text)) filters.push('inheritance_scam_filter');
|
|
10810
|
-
if (/password\s+reset|verify\s+account/i.test(text)) filters.push('account_verification_filter');
|
|
10694
|
+
// function detectBehavioralPatterns(body, subject) {
|
|
10695
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10696
|
+
// const patterns = [];
|
|
10811
10697
|
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
if (/webinar|event|conference/i.test(text)) filters.push('event_filter');
|
|
10698
|
+
// if (/(?:click|tap)\s+(?:here|this|link|button)/i.test(text)) {
|
|
10699
|
+
// patterns.push('call_to_action_link');
|
|
10700
|
+
// }
|
|
10816
10701
|
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
if (/appointment|meeting|reminder/i.test(text)) filters.push('calendar_filter');
|
|
10702
|
+
// if (/limited\s+time|offer\s+expires|only\s+\d+\s+left/i.test(text)) {
|
|
10703
|
+
// patterns.push('scarcity_tactic');
|
|
10704
|
+
// }
|
|
10821
10705
|
|
|
10822
|
-
|
|
10823
|
-
|
|
10706
|
+
// if (/\$\d+|\d+\s*%|\d+\s*off|discount|save|sale/i.test(text)) {
|
|
10707
|
+
// patterns.push('monetary_offer');
|
|
10708
|
+
// }
|
|
10824
10709
|
|
|
10825
|
-
|
|
10826
|
-
|
|
10827
|
-
|
|
10710
|
+
// if (/urgent|important|alert|attention|warning/i.test(text)) {
|
|
10711
|
+
// patterns.push('urgency_tactic');
|
|
10712
|
+
// }
|
|
10828
10713
|
|
|
10829
|
-
|
|
10830
|
-
|
|
10714
|
+
// if (/(?:please|kindly)\s+(?:help|assist|reply)/i.test(text)) {
|
|
10715
|
+
// patterns.push('polite_request');
|
|
10716
|
+
// }
|
|
10831
10717
|
|
|
10832
|
-
|
|
10833
|
-
|
|
10718
|
+
// if (/unsubscribe|opt.?out|preference|manage subscription/i.test(text)) {
|
|
10719
|
+
// patterns.push('subscription_management');
|
|
10720
|
+
// }
|
|
10834
10721
|
|
|
10835
|
-
|
|
10836
|
-
|
|
10722
|
+
// return patterns;
|
|
10723
|
+
// }
|
|
10837
10724
|
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
return /follow.?up|following.?up|checking.?in|touch.?base|re:.?re:/i.test(text);
|
|
10841
|
-
}
|
|
10725
|
+
// function assessDomainReputation(email) {
|
|
10726
|
+
// const domain = email.split('@')[1] || '';
|
|
10842
10727
|
|
|
10843
|
-
|
|
10844
|
-
|
|
10845
|
-
const nameParts = name.toLowerCase().split(' ');
|
|
10846
|
-
const firstName = nameParts[0] || '';
|
|
10728
|
+
// // Known spam domains (simplified list)
|
|
10729
|
+
// const spamDomains = ['spam4.me', 'trashmail.com', 'mailinator.com', 'guerrillamail.com', 'tempmail.com', 'yopmail.com', 'dispostable.com'];
|
|
10847
10730
|
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
has_greeting: /^(?:hi|hello|hey|dear|greetings)\b/im.test(body),
|
|
10852
|
-
has_signature: /(?:best|regards|sincerely|thanks|thank you)\s*[,]?\s*\n/im.test(body),
|
|
10853
|
-
has_questions: /\?/.test(text) && /(?:can|could|would|will|do|are|is)\s+you/i.test(text),
|
|
10854
|
-
};
|
|
10731
|
+
// if (spamDomains.includes(domain.toLowerCase())) {
|
|
10732
|
+
// return 'known_spam_domain';
|
|
10733
|
+
// }
|
|
10855
10734
|
|
|
10856
|
-
|
|
10735
|
+
// // Professional domains
|
|
10736
|
+
// const professionalTLDs = ['com', 'org', 'net', 'edu', 'gov', 'io', 'ai', 'tech'];
|
|
10737
|
+
// const tld = domain.split('.').pop() || '';
|
|
10857
10738
|
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
likely_known_sender: relationshipScore >= 40,
|
|
10862
|
-
};
|
|
10863
|
-
}
|
|
10739
|
+
// if (professionalTLDs.includes(tld.toLowerCase())) {
|
|
10740
|
+
// return 'professional_domain';
|
|
10741
|
+
// }
|
|
10864
10742
|
|
|
10865
|
-
|
|
10866
|
-
|
|
10743
|
+
// // New/suspicious TLDs
|
|
10744
|
+
// const suspiciousTLDs = ['xyz', 'top', 'win', 'bid', 'download', 'stream'];
|
|
10745
|
+
// if (suspiciousTLDs.includes(tld.toLowerCase())) {
|
|
10746
|
+
// return 'suspicious_tld';
|
|
10747
|
+
// }
|
|
10867
10748
|
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
confidence -= 20;
|
|
10871
|
-
}
|
|
10749
|
+
// return 'neutral';
|
|
10750
|
+
// }
|
|
10872
10751
|
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
confidence += 15;
|
|
10876
|
-
}
|
|
10752
|
+
// function calculateComprehensiveRisk(aiData, localAnalysis) {
|
|
10753
|
+
// let risk = 0;
|
|
10877
10754
|
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10755
|
+
// // Base on AI classification
|
|
10756
|
+
// switch (aiData.email_type) {
|
|
10757
|
+
// case 'spam':
|
|
10758
|
+
// risk += 80;
|
|
10759
|
+
// break;
|
|
10760
|
+
// case 'promotional':
|
|
10761
|
+
// risk += 30;
|
|
10762
|
+
// break;
|
|
10763
|
+
// case 'transactional':
|
|
10764
|
+
// risk += 10;
|
|
10765
|
+
// break;
|
|
10766
|
+
// case 'personal':
|
|
10767
|
+
// risk += 5;
|
|
10768
|
+
// break;
|
|
10769
|
+
// case 'business':
|
|
10770
|
+
// risk += 15;
|
|
10771
|
+
// break;
|
|
10772
|
+
// }
|
|
10882
10773
|
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
}
|
|
10774
|
+
// // Add local analysis scores
|
|
10775
|
+
// risk += localAnalysis.spamScore * 0.2;
|
|
10776
|
+
// risk += localAnalysis.phishingScore * 0.3;
|
|
10887
10777
|
|
|
10888
|
-
|
|
10889
|
-
|
|
10778
|
+
// // Adjust for phishing risk
|
|
10779
|
+
// switch (aiData.phishing_risk) {
|
|
10780
|
+
// case 'critical':
|
|
10781
|
+
// risk += 40;
|
|
10782
|
+
// break;
|
|
10783
|
+
// case 'high':
|
|
10784
|
+
// risk += 30;
|
|
10785
|
+
// break;
|
|
10786
|
+
// case 'medium':
|
|
10787
|
+
// risk += 15;
|
|
10788
|
+
// break;
|
|
10789
|
+
// case 'low':
|
|
10790
|
+
// risk += 5;
|
|
10791
|
+
// break;
|
|
10792
|
+
// }
|
|
10890
10793
|
|
|
10891
|
-
|
|
10892
|
-
|
|
10794
|
+
// // Adjust for unsolicited
|
|
10795
|
+
// if (aiData.is_unsolicited) risk += 20;
|
|
10893
10796
|
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
if (data.spam_confidence > 70) explanations.push(`- High spam confidence (${data.spam_confidence}%)`);
|
|
10897
|
-
if (data.phishing_risk !== 'none') explanations.push(`- ${data.phishing_risk} phishing risk`);
|
|
10898
|
-
if (data.local_analysis.spamScore > 60) explanations.push('- Contains spam indicators');
|
|
10899
|
-
}
|
|
10797
|
+
// // Adjust for urgency
|
|
10798
|
+
// if (aiData.is_urgent) risk += 10;
|
|
10900
10799
|
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
if (data.is_commercial) explanations.push('- Commercial intent detected');
|
|
10904
|
-
if (data.local_analysis.hasUnsubscribe) explanations.push('- Contains unsubscribe option');
|
|
10905
|
-
if (data.local_analysis.promotionalScore > 30) explanations.push('- Promotional content detected');
|
|
10906
|
-
}
|
|
10800
|
+
// return Math.min(risk, 100);
|
|
10801
|
+
// }
|
|
10907
10802
|
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
explanations.push(`- ${indicator}`);
|
|
10912
|
-
});
|
|
10913
|
-
}
|
|
10803
|
+
// function detectMatchedFilters(body, subject, email, name) {
|
|
10804
|
+
// const filters = [];
|
|
10805
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10914
10806
|
|
|
10915
|
-
|
|
10916
|
-
|
|
10807
|
+
// // Spam filters
|
|
10808
|
+
// if (/(?:viagra|cialis|penis|enlarge)/i.test(text)) filters.push('adult_content_filter');
|
|
10809
|
+
// if (/(?:lottery|winner|prize|jackpot)/i.test(text)) filters.push('lottery_scam_filter');
|
|
10810
|
+
// if (/(?:nigerian|prince|inheritance|unclaimed)/i.test(text)) filters.push('inheritance_scam_filter');
|
|
10811
|
+
// if (/password\s+reset|verify\s+account/i.test(text)) filters.push('account_verification_filter');
|
|
10917
10812
|
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10813
|
+
// // Promotional filters
|
|
10814
|
+
// if (/newsletter|subscribe|unsubscribe/i.test(text)) filters.push('newsletter_filter');
|
|
10815
|
+
// if (/sale|discount|offer|coupon/i.test(text)) filters.push('promotional_offer_filter');
|
|
10816
|
+
// if (/webinar|event|conference/i.test(text)) filters.push('event_filter');
|
|
10921
10817
|
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10818
|
+
// // Transactional filters
|
|
10819
|
+
// if (/order|invoice|receipt|payment/i.test(text)) filters.push('transaction_filter');
|
|
10820
|
+
// if (/shipping|delivery|tracking/i.test(text)) filters.push('shipping_filter');
|
|
10821
|
+
// if (/appointment|meeting|reminder/i.test(text)) filters.push('calendar_filter');
|
|
10926
10822
|
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
}
|
|
10823
|
+
// return filters;
|
|
10824
|
+
// }
|
|
10930
10825
|
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10826
|
+
// function detectTimeSensitivity(body) {
|
|
10827
|
+
// const text = body.toLowerCase();
|
|
10828
|
+
// const patterns = [/today|tomorrow|this\s+week|immediately|asap/i, /deadline|due\s+by|expires|limited\s+time/i, /urgent|important|attention|alert/i];
|
|
10934
10829
|
|
|
10935
|
-
|
|
10936
|
-
|
|
10937
|
-
flags.push('gdpr_mentions');
|
|
10938
|
-
}
|
|
10830
|
+
// return patterns.some((pattern) => pattern.test(text));
|
|
10831
|
+
// }
|
|
10939
10832
|
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
}
|
|
10833
|
+
// function detectExpiryDate(body) {
|
|
10834
|
+
// const datePatterns = [/\b\d{1,2}\/\d{1,2}\/\d{2,4}\b/g, /\b\d{1,2}\s+(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\s+\d{2,4}\b/gi, /\bexpires?\s+(?:on|by)?\s*[:]?\s*\d{1,2}\/\d{1,2}\/\d{2,4}\b/gi];
|
|
10943
10835
|
|
|
10944
|
-
|
|
10945
|
-
|
|
10836
|
+
// return datePatterns.some((pattern) => pattern.test(body.toLowerCase()));
|
|
10837
|
+
// }
|
|
10946
10838
|
|
|
10947
|
-
|
|
10948
|
-
|
|
10839
|
+
// function detectFollowUpPattern(body, subject) {
|
|
10840
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10841
|
+
// return /follow.?up|following.?up|checking.?in|touch.?base|re:.?re:/i.test(text);
|
|
10842
|
+
// }
|
|
10949
10843
|
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
|
|
10844
|
+
// function analyzeRelationshipContext(body, subject, name) {
|
|
10845
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10846
|
+
// const nameParts = name.toLowerCase().split(' ');
|
|
10847
|
+
// const firstName = nameParts[0] || '';
|
|
10848
|
+
|
|
10849
|
+
// const indicators = {
|
|
10850
|
+
// uses_name: firstName && text.includes(firstName),
|
|
10851
|
+
// uses_personal_pronouns: /\b(?:i|me|my|mine|you|your|yours)\b/gi.test(text),
|
|
10852
|
+
// has_greeting: /^(?:hi|hello|hey|dear|greetings)\b/im.test(body),
|
|
10853
|
+
// has_signature: /(?:best|regards|sincerely|thanks|thank you)\s*[,]?\s*\n/im.test(body),
|
|
10854
|
+
// has_questions: /\?/.test(text) && /(?:can|could|would|will|do|are|is)\s+you/i.test(text),
|
|
10855
|
+
// };
|
|
10955
10856
|
|
|
10956
|
-
|
|
10957
|
-
const phishingRisk = localAnalysis.phishingScore > 50 ? 'medium' : 'low';
|
|
10857
|
+
// const relationshipScore = Object.values(indicators).filter(Boolean).length * 20;
|
|
10958
10858
|
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10859
|
+
// return {
|
|
10860
|
+
// ...indicators,
|
|
10861
|
+
// relationship_score: Math.min(relationshipScore, 100),
|
|
10862
|
+
// likely_known_sender: relationshipScore >= 40,
|
|
10863
|
+
// };
|
|
10864
|
+
// }
|
|
10964
10865
|
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
malware_risk: 'none',
|
|
10866
|
+
// function calculateFinalConfidence(data) {
|
|
10867
|
+
// let confidence = data.email_type_confidence;
|
|
10968
10868
|
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
|
|
10869
|
+
// // Adjust based on local analysis
|
|
10870
|
+
// if (data.local_analysis.spamScore > 70 && data.email_type !== 'spam') {
|
|
10871
|
+
// confidence -= 20;
|
|
10872
|
+
// }
|
|
10973
10873
|
|
|
10974
|
-
|
|
10975
|
-
|
|
10874
|
+
// // Adjust based on phishing risk
|
|
10875
|
+
// if (data.phishing_risk === 'critical' || data.phishing_risk === 'high') {
|
|
10876
|
+
// confidence += 15;
|
|
10877
|
+
// }
|
|
10976
10878
|
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
contains_address: localAnalysis.hasAddress,
|
|
10879
|
+
// // Adjust based on personalization
|
|
10880
|
+
// if (data.is_personalized) {
|
|
10881
|
+
// confidence += 10;
|
|
10882
|
+
// }
|
|
10982
10883
|
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10884
|
+
// // Adjust based on content stats
|
|
10885
|
+
// if (data.content_stats.link_count > 5) {
|
|
10886
|
+
// confidence += 5;
|
|
10887
|
+
// }
|
|
10986
10888
|
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
inbox_priority: emailType === 'spam' ? 'ignore' : 'normal',
|
|
10889
|
+
// return Math.max(0, Math.min(100, confidence));
|
|
10890
|
+
// }
|
|
10990
10891
|
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
legitimacy_signals: [],
|
|
10892
|
+
// function generateExplanation(data) {
|
|
10893
|
+
// const explanations = [];
|
|
10994
10894
|
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10895
|
+
// if (data.email_type === 'spam') {
|
|
10896
|
+
// explanations.push('Classified as spam due to:');
|
|
10897
|
+
// if (data.spam_confidence > 70) explanations.push(`- High spam confidence (${data.spam_confidence}%)`);
|
|
10898
|
+
// if (data.phishing_risk !== 'none') explanations.push(`- ${data.phishing_risk} phishing risk`);
|
|
10899
|
+
// if (data.local_analysis.spamScore > 60) explanations.push('- Contains spam indicators');
|
|
10900
|
+
// }
|
|
10998
10901
|
|
|
10999
|
-
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
link_count: localAnalysis.linkCount,
|
|
11006
|
-
uppercase_ratio: calculateUppercaseRatio(emailBody),
|
|
11007
|
-
exclamation_count: (emailBody.match(/!/g) || []).length,
|
|
11008
|
-
dollar_sign_count: (emailBody.match(/\$/g) || []).length,
|
|
11009
|
-
phone_patterns: (emailBody.match(/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g) || []).length,
|
|
11010
|
-
},
|
|
10902
|
+
// if (data.email_type === 'promotional') {
|
|
10903
|
+
// explanations.push('Classified as promotional due to:');
|
|
10904
|
+
// if (data.is_commercial) explanations.push('- Commercial intent detected');
|
|
10905
|
+
// if (data.local_analysis.hasUnsubscribe) explanations.push('- Contains unsubscribe option');
|
|
10906
|
+
// if (data.local_analysis.promotionalScore > 30) explanations.push('- Promotional content detected');
|
|
10907
|
+
// }
|
|
11011
10908
|
|
|
11012
|
-
|
|
10909
|
+
// if (data.key_indicators && data.key_indicators.length > 0) {
|
|
10910
|
+
// explanations.push('Key indicators:');
|
|
10911
|
+
// data.key_indicators.forEach((indicator) => {
|
|
10912
|
+
// explanations.push(`- ${indicator}`);
|
|
10913
|
+
// });
|
|
10914
|
+
// }
|
|
11013
10915
|
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
error: error || 'API call failed',
|
|
11017
|
-
};
|
|
11018
|
-
}
|
|
10916
|
+
// return explanations.join('\n');
|
|
10917
|
+
// }
|
|
11019
10918
|
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
10919
|
+
// function checkCompliance(body, subject) {
|
|
10920
|
+
// const text = (subject + ' ' + body).toLowerCase();
|
|
10921
|
+
// const flags = [];
|
|
11023
10922
|
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
10923
|
+
// // CAN-SPAM Act compliance (US)
|
|
10924
|
+
// if (text.includes('unsubscribe') || text.includes('opt-out')) {
|
|
10925
|
+
// flags.push('has_unsubscribe_option');
|
|
10926
|
+
// }
|
|
11027
10927
|
|
|
11028
|
-
|
|
10928
|
+
// if (/\b\d{10}\b/.test(body.replace(/\D/g, ''))) {
|
|
10929
|
+
// flags.push('contains_phone_number');
|
|
10930
|
+
// }
|
|
11029
10931
|
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
- Poor grammar/spelling
|
|
11034
|
-
- Urgent/panic-inducing language
|
|
11035
|
-
- Requests for personal information
|
|
11036
|
-
- Too good to be true offers
|
|
11037
|
-
- Hidden/unclear sender identity
|
|
11038
|
-
- Multiple recipient addresses visible
|
|
11039
|
-
- Stock/"spammy" subject lines
|
|
11040
|
-
|
|
11041
|
-
PROMOTIONAL INDICATORS:
|
|
11042
|
-
- Marketing/sales content
|
|
11043
|
-
- Product announcements
|
|
11044
|
-
- Newsletter content
|
|
11045
|
-
- Discount/coupon offers
|
|
11046
|
-
- Event invitations (commercial)
|
|
11047
|
-
- Company updates (marketing focused)
|
|
11048
|
-
- Clear opt-out/unsubscribe option
|
|
11049
|
-
- Professional branding/templates
|
|
11050
|
-
- Call-to-action buttons
|
|
11051
|
-
|
|
11052
|
-
TRANSACTIONAL INDICATORS:
|
|
11053
|
-
- Order confirmations
|
|
11054
|
-
- Shipping notifications
|
|
11055
|
-
- Invoice/billing
|
|
11056
|
-
- Account notifications
|
|
11057
|
-
- Password resets
|
|
11058
|
-
- Booking confirmations
|
|
11059
|
-
- Appointment reminders
|
|
11060
|
-
- Payment receipts
|
|
11061
|
-
- Service updates
|
|
11062
|
-
|
|
11063
|
-
PERSONAL/BUSINESS INDICATORS:
|
|
11064
|
-
- Direct communication to you
|
|
11065
|
-
- Known sender relationship
|
|
11066
|
-
- Work/project related
|
|
11067
|
-
- Personal conversations
|
|
11068
|
-
- One-on-one correspondence
|
|
11069
|
-
- Contains your name specifically
|
|
11070
|
-
- Contextually relevant to you
|
|
11071
|
-
|
|
11072
|
-
ADDITIONAL FACTORS TO CONSIDER:
|
|
11073
|
-
- Sender reputation (company vs personal)
|
|
11074
|
-
- Your relationship with sender
|
|
11075
|
-
- Email formatting quality
|
|
11076
|
-
- Personalization level
|
|
11077
|
-
- Expected vs unexpected content
|
|
11078
|
-
- Action requested (if any)
|
|
11079
|
-
|
|
11080
|
-
PROVIDE DETAILED ANALYSIS WITH CONFIDENCE SCORES.`,
|
|
11081
|
-
model: 'gpt-5-nano',
|
|
11082
|
-
response_format: z.object({
|
|
11083
|
-
// Primary Classification
|
|
11084
|
-
email_type: z.enum(['spam', 'promotional', 'transactional', 'personal', 'business', 'ambiguous']),
|
|
11085
|
-
email_type_confidence: z.number().min(0).max(100),
|
|
11086
|
-
|
|
11087
|
-
// Sub-classification
|
|
11088
|
-
email_subtype: z.enum([
|
|
11089
|
-
// Spam types
|
|
11090
|
-
'phishing_attempt',
|
|
11091
|
-
'scam_offer',
|
|
11092
|
-
'malware_risk',
|
|
11093
|
-
'adult_content',
|
|
11094
|
-
'financial_scam',
|
|
11095
|
-
'lottery_scam',
|
|
11096
|
-
'inheritance_scam',
|
|
11097
|
-
'romance_scam',
|
|
11098
|
-
'tech_support_scam',
|
|
11099
|
-
|
|
11100
|
-
// Promotional types
|
|
11101
|
-
'marketing_newsletter',
|
|
11102
|
-
'product_announcement',
|
|
11103
|
-
'discount_offer',
|
|
11104
|
-
'event_invitation',
|
|
11105
|
-
'company_update',
|
|
11106
|
-
'blog_newsletter',
|
|
11107
|
-
'educational_content',
|
|
11108
|
-
'lead_magnet',
|
|
11109
|
-
|
|
11110
|
-
// Transactional types
|
|
11111
|
-
'order_confirmation',
|
|
11112
|
-
'shipping_notification',
|
|
11113
|
-
'invoice_billing',
|
|
11114
|
-
'payment_receipt',
|
|
11115
|
-
'account_verification',
|
|
11116
|
-
'password_reset',
|
|
11117
|
-
'appointment_reminder',
|
|
11118
|
-
'service_notification',
|
|
11119
|
-
|
|
11120
|
-
// Personal/Business types
|
|
11121
|
-
'personal_message',
|
|
11122
|
-
'work_collaboration',
|
|
11123
|
-
'client_communication',
|
|
11124
|
-
'team_announcement',
|
|
11125
|
-
'meeting_invitation',
|
|
11126
|
-
'project_update',
|
|
11127
|
-
'direct_inquiry',
|
|
11128
|
-
'networking_request',
|
|
11129
|
-
]),
|
|
10932
|
+
// if (/address\s*[:]?\s*\d+\s+[\w\s]+/i.test(body)) {
|
|
10933
|
+
// flags.push('contains_physical_address');
|
|
10934
|
+
// }
|
|
11130
10935
|
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
10936
|
+
// // GDPR indicators (EU)
|
|
10937
|
+
// if (/privacy\s+policy|gdpr|data\s+protection/i.test(text)) {
|
|
10938
|
+
// flags.push('gdpr_mentions');
|
|
10939
|
+
// }
|
|
11135
10940
|
|
|
11136
|
-
|
|
11137
|
-
|
|
11138
|
-
|
|
11139
|
-
is_urgent: z.boolean().describe('Uses urgent/time-sensitive language'),
|
|
11140
|
-
is_personalized: z.boolean().describe('Content is personalized to recipient'),
|
|
10941
|
+
// if (/consent|opt.?in|permission/i.test(text)) {
|
|
10942
|
+
// flags.push('consent_mentions');
|
|
10943
|
+
// }
|
|
11141
10944
|
|
|
11142
|
-
|
|
11143
|
-
|
|
11144
|
-
sender_intent: z.enum(['inform', 'sell', 'scam', 'build_relationship', 'request_action', 'unknown']),
|
|
10945
|
+
// return flags;
|
|
10946
|
+
// }
|
|
11145
10947
|
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
contains_attachments: z.boolean(),
|
|
11149
|
-
contains_unsubscribe: z.boolean(),
|
|
11150
|
-
contains_phone_number: z.boolean(),
|
|
11151
|
-
contains_address: z.boolean(),
|
|
10948
|
+
// function getDefaultEmailDetection(name, email, emailBody, emailSubject, error = null) {
|
|
10949
|
+
// const localAnalysis = analyzeEmailLocally(emailBody, emailSubject, email, name);
|
|
11152
10950
|
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
10951
|
+
// // Determine type based on local analysis
|
|
10952
|
+
// let emailType = 'ambiguous';
|
|
10953
|
+
// if (localAnalysis.spamScore > 70) emailType = 'spam';
|
|
10954
|
+
// else if (localAnalysis.promotionalScore > localAnalysis.transactionalScore && localAnalysis.promotionalScore > 30) emailType = 'promotional';
|
|
10955
|
+
// else if (localAnalysis.transactionalScore > 40) emailType = 'transactional';
|
|
11157
10956
|
|
|
11158
|
-
|
|
11159
|
-
|
|
10957
|
+
// const spamConfidence = localAnalysis.spamScore;
|
|
10958
|
+
// const phishingRisk = localAnalysis.phishingScore > 50 ? 'medium' : 'low';
|
|
11160
10959
|
|
|
11161
|
-
|
|
11162
|
-
|
|
10960
|
+
// return {
|
|
10961
|
+
// success: false,
|
|
10962
|
+
// email_type: emailType,
|
|
10963
|
+
// email_type_confidence: Math.max(50, spamConfidence),
|
|
10964
|
+
// email_subtype: 'personal_message',
|
|
10965
|
+
|
|
10966
|
+
// spam_confidence: spamConfidence,
|
|
10967
|
+
// phishing_risk: phishingRisk,
|
|
10968
|
+
// malware_risk: 'none',
|
|
10969
|
+
|
|
10970
|
+
// is_unsolicited: true,
|
|
10971
|
+
// is_commercial: localAnalysis.promotionalScore > 30,
|
|
10972
|
+
// is_urgent: localAnalysis.urgencyCount > 0,
|
|
10973
|
+
// is_personalized: localAnalysis.personalizationScore > 20,
|
|
10974
|
+
|
|
10975
|
+
// sender_legitimacy: 'unknown',
|
|
10976
|
+
// sender_intent: 'unknown',
|
|
10977
|
+
|
|
10978
|
+
// contains_links: localAnalysis.linkCount > 0,
|
|
10979
|
+
// contains_attachments: false,
|
|
10980
|
+
// contains_unsubscribe: localAnalysis.hasUnsubscribe,
|
|
10981
|
+
// contains_phone_number: localAnalysis.hasPhone,
|
|
10982
|
+
// contains_address: localAnalysis.hasAddress,
|
|
10983
|
+
|
|
10984
|
+
// language_quality: localAnalysis.misspellingCount > 3 ? 'poor' : 'average',
|
|
10985
|
+
// urgency_level: localAnalysis.urgencyCount > 2 ? 'high' : 'low',
|
|
10986
|
+
// personalization_score: localAnalysis.personalizationScore,
|
|
10987
|
+
|
|
10988
|
+
// suggested_action: emailType === 'spam' ? 'mark_as_spam' : 'keep_in_inbox',
|
|
10989
|
+
// auto_filter_suggestion: emailType === 'spam' ? 'spam_filter' : 'no_filter',
|
|
10990
|
+
// inbox_priority: emailType === 'spam' ? 'ignore' : 'normal',
|
|
10991
|
+
|
|
10992
|
+
// key_indicators: ['Local analysis only - API failed'],
|
|
10993
|
+
// risk_factors: [],
|
|
10994
|
+
// legitimacy_signals: [],
|
|
10995
|
+
|
|
10996
|
+
// analysis_timestamp: new Date().toISOString(),
|
|
10997
|
+
// content_length: emailBody.length,
|
|
10998
|
+
// analysis_complexity: 'simple',
|
|
10999
|
+
|
|
11000
|
+
// // Enhanced fields
|
|
11001
|
+
// local_analysis: localAnalysis,
|
|
11002
|
+
// sender_analysis: analyzeSender(email, name, emailBody),
|
|
11003
|
+
// content_stats: {
|
|
11004
|
+
// word_count: (emailBody.match(/\S+/g) || []).length,
|
|
11005
|
+
// sentence_count: (emailBody.match(/[.!?]+/g) || []).length,
|
|
11006
|
+
// link_count: localAnalysis.linkCount,
|
|
11007
|
+
// uppercase_ratio: calculateUppercaseRatio(emailBody),
|
|
11008
|
+
// exclamation_count: (emailBody.match(/!/g) || []).length,
|
|
11009
|
+
// dollar_sign_count: (emailBody.match(/\$/g) || []).length,
|
|
11010
|
+
// phone_patterns: (emailBody.match(/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g) || []).length,
|
|
11011
|
+
// },
|
|
11163
11012
|
|
|
11164
|
-
|
|
11165
|
-
inbox_priority: z.enum(['critical', 'high', 'normal', 'low', 'ignore']),
|
|
11013
|
+
// comprehensive_risk_score: calculateComprehensiveRisk({ email_type: emailType, phishing_risk: phishingRisk, is_unsolicited: true, is_urgent: localAnalysis.urgencyCount > 0 }, localAnalysis),
|
|
11166
11014
|
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11015
|
+
// final_confidence: Math.max(50, spamConfidence),
|
|
11016
|
+
// explanation: 'Default analysis due to API failure',
|
|
11017
|
+
// error: error || 'API call failed',
|
|
11018
|
+
// };
|
|
11019
|
+
// }
|
|
11171
11020
|
|
|
11172
|
-
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11021
|
+
// const detection_ret = await submit_chat_gpt_prompt({
|
|
11022
|
+
// uid,
|
|
11023
|
+
// prompt: `Analyze this email and determine if it's SPAM, PROMOTIONAL, TRANSACTIONAL, or PERSONAL/BUSINESS communication.
|
|
11024
|
+
|
|
11025
|
+
// FROM: "${name}" <${email}>
|
|
11026
|
+
// SUBJECT: "${email_subject}"
|
|
11027
|
+
// BODY: "${email_body.substring(0, 800)}${email_body.length > 800 ? '...' : ''}"
|
|
11028
|
+
|
|
11029
|
+
// ANALYSIS CRITERIA:
|
|
11030
|
+
|
|
11031
|
+
// SPAM INDICATORS:
|
|
11032
|
+
// - Unsolicited commercial content
|
|
11033
|
+
// - Phishing attempts or suspicious links
|
|
11034
|
+
// - Poor grammar/spelling
|
|
11035
|
+
// - Urgent/panic-inducing language
|
|
11036
|
+
// - Requests for personal information
|
|
11037
|
+
// - Too good to be true offers
|
|
11038
|
+
// - Hidden/unclear sender identity
|
|
11039
|
+
// - Multiple recipient addresses visible
|
|
11040
|
+
// - Stock/"spammy" subject lines
|
|
11041
|
+
|
|
11042
|
+
// PROMOTIONAL INDICATORS:
|
|
11043
|
+
// - Marketing/sales content
|
|
11044
|
+
// - Product announcements
|
|
11045
|
+
// - Newsletter content
|
|
11046
|
+
// - Discount/coupon offers
|
|
11047
|
+
// - Event invitations (commercial)
|
|
11048
|
+
// - Company updates (marketing focused)
|
|
11049
|
+
// - Clear opt-out/unsubscribe option
|
|
11050
|
+
// - Professional branding/templates
|
|
11051
|
+
// - Call-to-action buttons
|
|
11052
|
+
|
|
11053
|
+
// TRANSACTIONAL INDICATORS:
|
|
11054
|
+
// - Order confirmations
|
|
11055
|
+
// - Shipping notifications
|
|
11056
|
+
// - Invoice/billing
|
|
11057
|
+
// - Account notifications
|
|
11058
|
+
// - Password resets
|
|
11059
|
+
// - Booking confirmations
|
|
11060
|
+
// - Appointment reminders
|
|
11061
|
+
// - Payment receipts
|
|
11062
|
+
// - Service updates
|
|
11063
|
+
|
|
11064
|
+
// PERSONAL/BUSINESS INDICATORS:
|
|
11065
|
+
// - Direct communication to you
|
|
11066
|
+
// - Known sender relationship
|
|
11067
|
+
// - Work/project related
|
|
11068
|
+
// - Personal conversations
|
|
11069
|
+
// - One-on-one correspondence
|
|
11070
|
+
// - Contains your name specifically
|
|
11071
|
+
// - Contextually relevant to you
|
|
11072
|
+
|
|
11073
|
+
// ADDITIONAL FACTORS TO CONSIDER:
|
|
11074
|
+
// - Sender reputation (company vs personal)
|
|
11075
|
+
// - Your relationship with sender
|
|
11076
|
+
// - Email formatting quality
|
|
11077
|
+
// - Personalization level
|
|
11078
|
+
// - Expected vs unexpected content
|
|
11079
|
+
// - Action requested (if any)
|
|
11080
|
+
|
|
11081
|
+
// PROVIDE DETAILED ANALYSIS WITH CONFIDENCE SCORES.`,
|
|
11082
|
+
// model: 'gpt-5-nano',
|
|
11083
|
+
// response_format: z.object({
|
|
11084
|
+
// // Primary Classification
|
|
11085
|
+
// email_type: z.enum(['spam', 'promotional', 'transactional', 'personal', 'business', 'ambiguous']),
|
|
11086
|
+
// email_type_confidence: z.number().min(0).max(100),
|
|
11087
|
+
|
|
11088
|
+
// // Sub-classification
|
|
11089
|
+
// email_subtype: z.enum([
|
|
11090
|
+
// // Spam types
|
|
11091
|
+
// 'phishing_attempt',
|
|
11092
|
+
// 'scam_offer',
|
|
11093
|
+
// 'malware_risk',
|
|
11094
|
+
// 'adult_content',
|
|
11095
|
+
// 'financial_scam',
|
|
11096
|
+
// 'lottery_scam',
|
|
11097
|
+
// 'inheritance_scam',
|
|
11098
|
+
// 'romance_scam',
|
|
11099
|
+
// 'tech_support_scam',
|
|
11100
|
+
|
|
11101
|
+
// // Promotional types
|
|
11102
|
+
// 'marketing_newsletter',
|
|
11103
|
+
// 'product_announcement',
|
|
11104
|
+
// 'discount_offer',
|
|
11105
|
+
// 'event_invitation',
|
|
11106
|
+
// 'company_update',
|
|
11107
|
+
// 'blog_newsletter',
|
|
11108
|
+
// 'educational_content',
|
|
11109
|
+
// 'lead_magnet',
|
|
11110
|
+
|
|
11111
|
+
// // Transactional types
|
|
11112
|
+
// 'order_confirmation',
|
|
11113
|
+
// 'shipping_notification',
|
|
11114
|
+
// 'invoice_billing',
|
|
11115
|
+
// 'payment_receipt',
|
|
11116
|
+
// 'account_verification',
|
|
11117
|
+
// 'password_reset',
|
|
11118
|
+
// 'appointment_reminder',
|
|
11119
|
+
// 'service_notification',
|
|
11120
|
+
|
|
11121
|
+
// // Personal/Business types
|
|
11122
|
+
// 'personal_message',
|
|
11123
|
+
// 'work_collaboration',
|
|
11124
|
+
// 'client_communication',
|
|
11125
|
+
// 'team_announcement',
|
|
11126
|
+
// 'meeting_invitation',
|
|
11127
|
+
// 'project_update',
|
|
11128
|
+
// 'direct_inquiry',
|
|
11129
|
+
// 'networking_request',
|
|
11130
|
+
// ]),
|
|
11131
|
+
|
|
11132
|
+
// // Risk Assessment
|
|
11133
|
+
// spam_confidence: z.number().min(0).max(100).describe('Confidence this is spam'),
|
|
11134
|
+
// phishing_risk: z.enum(['none', 'low', 'medium', 'high', 'critical']),
|
|
11135
|
+
// malware_risk: z.enum(['none', 'low', 'medium', 'high']),
|
|
11136
|
+
|
|
11137
|
+
// // Content Analysis
|
|
11138
|
+
// is_unsolicited: z.boolean().describe('Email was not requested/expected'),
|
|
11139
|
+
// is_commercial: z.boolean().describe('Contains commercial intent'),
|
|
11140
|
+
// is_urgent: z.boolean().describe('Uses urgent/time-sensitive language'),
|
|
11141
|
+
// is_personalized: z.boolean().describe('Content is personalized to recipient'),
|
|
11142
|
+
|
|
11143
|
+
// // Sender Analysis
|
|
11144
|
+
// sender_legitimacy: z.enum(['verified', 'likely_legitimate', 'suspicious', 'likely_fake', 'unknown']),
|
|
11145
|
+
// sender_intent: z.enum(['inform', 'sell', 'scam', 'build_relationship', 'request_action', 'unknown']),
|
|
11146
|
+
|
|
11147
|
+
// // Content Characteristics
|
|
11148
|
+
// contains_links: z.boolean(),
|
|
11149
|
+
// contains_attachments: z.boolean(),
|
|
11150
|
+
// contains_unsubscribe: z.boolean(),
|
|
11151
|
+
// contains_phone_number: z.boolean(),
|
|
11152
|
+
// contains_address: z.boolean(),
|
|
11153
|
+
|
|
11154
|
+
// // Language Analysis
|
|
11155
|
+
// language_quality: z.enum(['excellent', 'good', 'average', 'poor', 'spammy']),
|
|
11156
|
+
// urgency_level: z.enum(['none', 'low', 'medium', 'high', 'extreme']),
|
|
11157
|
+
// personalization_score: z.number().min(0).max(100).describe('How personalized the content is'),
|
|
11158
|
+
|
|
11159
|
+
// // Action Recommendations
|
|
11160
|
+
// suggested_action: z.enum(['delete_immediately', 'mark_as_spam', 'move_to_promotions', 'respond_politely', 'follow_up', 'archive', 'keep_in_inbox', 'add_to_contacts', 'report_phishing']),
|
|
11161
|
+
|
|
11162
|
+
// // Filter Recommendations
|
|
11163
|
+
// auto_filter_suggestion: z.enum(['spam_filter', 'promotions_filter', 'social_filter', 'updates_filter', 'primary_inbox', 'no_filter']),
|
|
11164
|
+
|
|
11165
|
+
// // Priority
|
|
11166
|
+
// inbox_priority: z.enum(['critical', 'high', 'normal', 'low', 'ignore']),
|
|
11167
|
+
|
|
11168
|
+
// // Detailed Analysis
|
|
11169
|
+
// key_indicators: z.array(z.string()).describe('Key factors influencing classification'),
|
|
11170
|
+
// risk_factors: z.array(z.string()).describe('Specific risks identified'),
|
|
11171
|
+
// legitimacy_signals: z.array(z.string()).describe('Signals of legitimate communication'),
|
|
11172
|
+
|
|
11173
|
+
// // Metadata
|
|
11174
|
+
// analysis_timestamp: z.string(),
|
|
11175
|
+
// content_length: z.number().describe('Length of email body analyzed'),
|
|
11176
|
+
// analysis_complexity: z.enum(['simple', 'moderate', 'complex', 'ambiguous']),
|
|
11177
|
+
// }),
|
|
11178
|
+
// metadata: {
|
|
11179
|
+
// func: 'detect_email_type',
|
|
11180
|
+
// sender_name: name,
|
|
11181
|
+
// sender_email: email,
|
|
11182
|
+
// subject_length: email_subject?.length || 0,
|
|
11183
|
+
// body_length: email_body?.length || 0,
|
|
11184
|
+
// body_preview_hash: await hashString(email_body.substring(0, 200)),
|
|
11185
|
+
// },
|
|
11186
|
+
// account_profile_info,
|
|
11187
|
+
// tools: [{ type: 'web_search_preview' }],
|
|
11188
|
+
// });
|
|
11188
11189
|
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11190
|
+
// try {
|
|
11191
|
+
// if (detection_ret.code > -1) {
|
|
11192
|
+
// const data = typeof detection_ret.data === 'string' ? JSON.parse(detection_ret.data) : detection_ret.data;
|
|
11192
11193
|
|
|
11193
|
-
|
|
11194
|
-
|
|
11194
|
+
// // Enhance with additional analysis
|
|
11195
|
+
// const enhancedData = enhanceEmailDetection(data, name, email, email_body, email_subject);
|
|
11195
11196
|
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
};
|
|
11197
|
+
// return {
|
|
11198
|
+
// success: true,
|
|
11199
|
+
// ...enhancedData,
|
|
11200
|
+
// };
|
|
11201
|
+
// } else {
|
|
11202
|
+
// console.error('Email detection API call failed:', detection_ret);
|
|
11203
|
+
// return getDefaultEmailDetection(name, email, email_body, email_subject);
|
|
11204
|
+
// }
|
|
11205
|
+
// } catch (error) {
|
|
11206
|
+
// console.error('Error in detect_email_type:', error);
|
|
11207
|
+
// return getDefaultEmailDetection(name, email, email_body, email_subject, error.message);
|
|
11208
|
+
// }
|
|
11209
|
+
// };
|