diff --git a/EmailSearch/EmailSearchTools.cs b/EmailSearch/EmailSearchTools.cs index 29dca91..f879424 100644 --- a/EmailSearch/EmailSearchTools.cs +++ b/EmailSearch/EmailSearchTools.cs @@ -80,13 +80,16 @@ public class EmailSearchTools public static string MoveToJunk( [Description("Exact or partial subject line to match")] string subject, [Description("Date of the email (supports: yyyy-MM-dd, MM/dd/yyyy, dd/MM/yyyy)")] string date, - [Description("Outlook folder to search for the email: Inbox, SentMail, Drafts, All, or any custom folder name (default Inbox)")] string folder = "Inbox") + [Description("Outlook folder to search for the email: Inbox, SentMail, Drafts, All, or any custom folder name (default Inbox)")] string folder = "Inbox", + [Description("Optional time to find the closest match when multiple emails share the same subject and date (e.g., '13:46', '1:46 PM')")] string? time = null) { try { if (!TryParseDate(date, out var targetDate)) return $"Invalid date format '{date}'. Supported formats: yyyy-MM-dd, MM/dd/yyyy, dd/MM/yyyy"; + TimeSpan? targetTime = TryParseTime(time); + using var outlookApp = new OutlookApp(); var ns = outlookApp.GetNamespace("MAPI"); var foldersToSearch = GetFoldersToSearch(ns, folder); @@ -94,7 +97,7 @@ public class EmailSearchTools foreach (var mailFolder in foldersToSearch) { - var mail = FindEmail(mailFolder, subject, targetDate); + var mail = FindEmail(mailFolder, subject, targetDate, targetTime); if (mail != null) { var emailSubject = mail.Subject; @@ -115,20 +118,23 @@ public class EmailSearchTools public static string ReadEmail( [Description("Exact or partial subject line to match")] string subject, [Description("Date of the email (supports: yyyy-MM-dd, MM/dd/yyyy, dd/MM/yyyy)")] string date, - [Description("Outlook folder: Inbox, SentMail, Drafts, DeletedItems, Junk, All, or any custom folder name (default All)")] string folder = "All") + [Description("Outlook folder: Inbox, SentMail, Drafts, DeletedItems, Junk, All, or any custom folder name (default All)")] string folder = "All", + [Description("Optional time to find the closest match when multiple emails share the same subject and date (e.g., '13:46', '1:46 PM')")] string? time = null) { try { if (!TryParseDate(date, out var targetDate)) return $"Invalid date format '{date}'. Supported formats: yyyy-MM-dd, MM/dd/yyyy, dd/MM/yyyy"; + TimeSpan? targetTime = TryParseTime(time); + using var outlookApp = new OutlookApp(); var ns = outlookApp.GetNamespace("MAPI"); var foldersToSearch = GetFoldersToSearch(ns, folder); foreach (var mailFolder in foldersToSearch) { - var mail = FindEmail(mailFolder, subject, targetDate); + var mail = FindEmail(mailFolder, subject, targetDate, targetTime); if (mail != null) return FormatFullEmail(mail); } @@ -145,20 +151,23 @@ public class EmailSearchTools public static string AnalyzeSpam( [Description("Exact or partial subject line to match")] string subject, [Description("Date of the email (supports: yyyy-MM-dd, MM/dd/yyyy, dd/MM/yyyy)")] string date, - [Description("Outlook folder: Inbox, SentMail, Drafts, DeletedItems, Junk, All, or any custom folder name (default All)")] string folder = "All") + [Description("Outlook folder: Inbox, SentMail, Drafts, DeletedItems, Junk, All, or any custom folder name (default All)")] string folder = "All", + [Description("Optional time to find the closest match when multiple emails share the same subject and date (e.g., '13:46', '1:46 PM')")] string? time = null) { try { if (!TryParseDate(date, out var targetDate)) return $"Invalid date format '{date}'. Supported formats: yyyy-MM-dd, MM/dd/yyyy, dd/MM/yyyy"; + TimeSpan? targetTime = TryParseTime(time); + using var outlookApp = new OutlookApp(); var ns = outlookApp.GetNamespace("MAPI"); var foldersToSearch = GetFoldersToSearch(ns, folder); foreach (var mailFolder in foldersToSearch) { - var mail = FindEmail(mailFolder, subject, targetDate); + var mail = FindEmail(mailFolder, subject, targetDate, targetTime); if (mail != null) { var detector = new SpamDetector(); @@ -436,7 +445,7 @@ public class EmailSearchTools } } - private static MailItem? FindEmail(MAPIFolder folder, string subject, DateTime targetDate) + private static MailItem? FindEmail(MAPIFolder folder, string subject, DateTime targetDate, TimeSpan? targetTime = null) { var items = folder.Items; items.Sort("[ReceivedTime]", true); @@ -445,6 +454,31 @@ public class EmailSearchTools var filter = $"[ReceivedTime] >= '{targetDate:MM/dd/yyyy}' AND [ReceivedTime] < '{targetDate.AddDays(1):MM/dd/yyyy}'"; var filteredItems = items.Restrict(filter); + if (targetTime.HasValue) + { + // Find the email closest to the specified time + var targetDateTime = targetDate.Date + targetTime.Value; + MailItem? bestMatch = null; + var bestDiff = TimeSpan.MaxValue; + + foreach (var item in filteredItems) + { + if (item is MailItem mail && + mail.Subject != null && + mail.Subject.Contains(subject, StringComparison.OrdinalIgnoreCase)) + { + var diff = (mail.ReceivedTime - targetDateTime).Duration(); + if (diff < bestDiff) + { + bestDiff = diff; + bestMatch = mail; + } + } + } + + return bestMatch; + } + foreach (var item in filteredItems) { if (item is MailItem mail && @@ -664,6 +698,17 @@ public class EmailSearchTools out result); } + private static TimeSpan? TryParseTime(string? timeString) + { + if (string.IsNullOrWhiteSpace(timeString)) + return null; + + if (DateTime.TryParse(timeString, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out var parsed)) + return parsed.TimeOfDay; + + return null; + } + private static OlImportance? ParseImportance(string? importance) { if (string.IsNullOrEmpty(importance)) return null;