-
Notifications
You must be signed in to change notification settings - Fork 324
feat: add sync_max_age_days to email adapter #547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -90,6 +90,7 @@ struct EmailPollConfig { | |
| poll_interval: Duration, | ||
| allowed_senders: Vec<String>, | ||
| max_body_bytes: usize, | ||
| sync_max_age_days: u64, | ||
| runtime_key: String, | ||
| } | ||
|
|
||
|
|
@@ -142,6 +143,7 @@ pub struct EmailAdapter { | |
| allowed_senders: Vec<String>, | ||
| max_body_bytes: usize, | ||
| max_attachment_bytes: usize, | ||
| sync_max_age_days: u64, | ||
| smtp_transport: AsyncSmtpTransport<Tokio1Executor>, | ||
| shutdown_tx: Arc<RwLock<Option<watch::Sender<bool>>>>, | ||
| poll_task: Arc<RwLock<Option<JoinHandle<()>>>>, | ||
|
|
@@ -199,6 +201,7 @@ impl EmailAdapter { | |
| allowed_senders: config.allowed_senders.clone(), | ||
| max_body_bytes: config.max_body_bytes, | ||
| max_attachment_bytes: config.max_attachment_bytes, | ||
| sync_max_age_days: config.sync_max_age_days, | ||
| instances: Vec::new(), | ||
| }; | ||
| Self::build(runtime_key.into(), &email_config) | ||
|
|
@@ -238,6 +241,7 @@ impl EmailAdapter { | |
| allowed_senders: config.allowed_senders.clone(), | ||
| max_body_bytes: config.max_body_bytes.max(1024), | ||
| max_attachment_bytes: config.max_attachment_bytes.max(1024), | ||
| sync_max_age_days: config.sync_max_age_days, | ||
| smtp_transport, | ||
| shutdown_tx: Arc::new(RwLock::new(None)), | ||
| poll_task: Arc::new(RwLock::new(None)), | ||
|
|
@@ -257,6 +261,7 @@ impl EmailAdapter { | |
| poll_interval: self.poll_interval, | ||
| allowed_senders: self.allowed_senders.clone(), | ||
| max_body_bytes: self.max_body_bytes, | ||
| sync_max_age_days: self.sync_max_age_days, | ||
| runtime_key: self.runtime_key.clone(), | ||
| } | ||
| } | ||
|
|
@@ -713,8 +718,19 @@ fn poll_inbox_once(config: &EmailPollConfig) -> anyhow::Result<Vec<InboundMessag | |
| continue; | ||
| } | ||
|
|
||
| // Combine UNSEEN with a SINCE date filter when sync_max_age_days is set, | ||
| // so first-connect doesn't flood the agent with years of unread email. | ||
| let search_query = if config.sync_max_age_days > 0 { | ||
| let since_date = (Utc::now() - ChronoDuration::days(config.sync_max_age_days as i64)) | ||
| .format("%d-%b-%Y") | ||
| .to_string(); | ||
|
Comment on lines
+723
to
+726
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Casting So if the
Example: If you don’t want this wraparound/negative behavior, use Citations:
Guard On line 724, casting Add bounds validation before the cast (preferably at config load time) or use 🤖 Prompt for AI Agents |
||
| format!("UNSEEN SINCE {since_date}") | ||
| } else { | ||
| "UNSEEN".to_string() | ||
| }; | ||
|
Comment on lines
+721
to
+730
|
||
|
|
||
| let message_uids = session | ||
| .uid_search("UNSEEN") | ||
| .uid_search(&search_query) | ||
| .with_context(|| format!("failed to search unseen messages in folder '{folder}'"))?; | ||
|
Comment on lines
+721
to
734
|
||
|
|
||
| for uid in message_uids { | ||
|
|
@@ -1210,6 +1226,7 @@ pub fn search_mailbox( | |
| poll_interval: Duration::from_secs(config.poll_interval_secs.max(5)), | ||
| allowed_senders: config.allowed_senders.clone(), | ||
| max_body_bytes: config.max_body_bytes.max(1024), | ||
| sync_max_age_days: config.sync_max_age_days, | ||
| runtime_key: "email".to_string(), | ||
| })?; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
config.sync_max_age_daysis au64but is cast toi64withas, which will wrap for values >i64::MAXand can produce a negative duration (leading to a futureSINCEdate or other incorrect behavior). Use a checked conversion (e.g.,i64::try_from(...)) and either clamp to a reasonable max or return a config/validation error when it doesn’t fit.