33from datetime import datetime , timedelta , timezone
44from typing import Optional
55
6- from inboxanchor .mail_intelligence import (
7- is_high_value_newsletter ,
8- looks_automated_email ,
9- recommend_mailbox_labels ,
10- )
6+ from inboxanchor .mail_intelligence import assign_single_label
117from inboxanchor .models import (
128 EmailClassification ,
139 EmailMessage ,
1410 EmailRecommendation ,
1511 WorkspacePolicy ,
1612)
1713from inboxanchor .models .email import EmailCategory , RecommendationStatus
14+ from inboxanchor .sender_intelligence import analyze_message_signals
1815
1916
2017class RulesEngine :
@@ -29,32 +26,78 @@ def recommend(
2926 now = now or datetime .now (timezone .utc )
3027 policy = policy or WorkspacePolicy ()
3128 age = now - email .received_at
32- labels = (
33- recommend_mailbox_labels (
34- sender = email .sender ,
35- subject = email .subject ,
36- snippet = email .snippet ,
37- body = email .content_for_processing (),
38- has_attachments = email .has_attachments ,
39- category = classification .category ,
40- priority = classification .priority ,
41- )
42- if policy .auto_label_recommendations
43- else []
44- )
45- automated = looks_automated_email (
29+ body = email .content_for_processing ()
30+ signals = analyze_message_signals (email )
31+ single_label = assign_single_label (
4632 sender = email .sender ,
4733 subject = email .subject ,
4834 snippet = email .snippet ,
49- body = email .content_for_processing (),
35+ body = body ,
36+ has_attachments = email .has_attachments ,
37+ signals = signals ,
5038 )
51- high_value_newsletter = is_high_value_newsletter (
52- sender = email .sender ,
53- subject = email .subject ,
54- snippet = email .snippet ,
55- body = email .content_for_processing (),
39+ labels = [single_label ] if policy .auto_label_recommendations else []
40+ automated = signals .automated
41+ high_value_newsletter = signals .high_value_newsletter
42+
43+ cleanup_guard = any (
44+ (
45+ email .has_attachments ,
46+ signals .finance_invoice ,
47+ signals .finance_receipt ,
48+ signals .security ,
49+ signals .reply_needed ,
50+ classification .category
51+ in {
52+ EmailCategory .urgent ,
53+ EmailCategory .work ,
54+ EmailCategory .finance ,
55+ EmailCategory .opportunity ,
56+ EmailCategory .personal ,
57+ },
58+ )
5659 )
5760
61+ if (
62+ single_label == "cleanup"
63+ and classification .category == EmailCategory .spam_like
64+ and classification .confidence >= 0.85
65+ and not cleanup_guard
66+ ):
67+ return EmailRecommendation (
68+ email_id = email .id ,
69+ recommended_action = "archive" ,
70+ reason = "Spam-like email detected — auto-archived." ,
71+ confidence = classification .confidence ,
72+ status = RecommendationStatus .safe ,
73+ requires_approval = False ,
74+ proposed_labels = labels ,
75+ )
76+
77+ if (
78+ single_label == "cleanup"
79+ and classification .category
80+ in {
81+ EmailCategory .promo ,
82+ EmailCategory .low_priority ,
83+ EmailCategory .unknown ,
84+ EmailCategory .newsletter ,
85+ }
86+ and automated
87+ and classification .confidence >= 0.80
88+ and not high_value_newsletter
89+ and not cleanup_guard
90+ ):
91+ return EmailRecommendation (
92+ email_id = email .id ,
93+ recommended_action = "archive" ,
94+ reason = "Low-value automated email — auto-archived." ,
95+ confidence = classification .confidence ,
96+ status = RecommendationStatus .safe ,
97+ requires_approval = False ,
98+ proposed_labels = labels ,
99+ )
100+
58101 if (
59102 policy .allow_newsletter_mark_read
60103 and classification .category == EmailCategory .newsletter
@@ -100,7 +143,7 @@ def recommend(
100143 confidence = classification .confidence ,
101144 status = RecommendationStatus .requires_approval ,
102145 requires_approval = True ,
103- proposed_labels = labels or ["cleanup/low-priority " ],
146+ proposed_labels = labels or ["cleanup" ],
104147 )
105148
106149 if (
0 commit comments