Refactor email filtering logic in LimilabsImapEmailService

Simplify email filtering by removing server-side filtering logic
and replacing it with in-process filtering after email retrieval.
Eliminate the use of `ICriterion` and `Expression` constructs,
and move all filtering conditions (e.g., `UnseenOnly`,
`SubjectContains`, `SenderContains`, etc.) into the processing
loop.

Add an `IsSeen` property to `ReceivedEmailContext` to track
email read status. Apply `filter.MaxCount` after all filtering
and processing are complete. Update `filter.WithAttachments`
logic to conditionally include attachments in results.

Improve code readability and maintainability by consolidating
filtering logic into a single location, ensuring consistent
application of all filters.
This commit is contained in:
2026-08-12 13:41:35 +02:00
parent f6ada2ad9e
commit 48796d9917

View File

@@ -37,35 +37,9 @@ public class LimilabsImapEmailService(
try
{
#region Find UIDs
// Server-side: only date range; all other filters are applied in-process after cache retrieval
List<ICriterion> criterions = [];
if (filter.UnseenOnly)
criterions.Add(Expression.HasFlag(Flag.Unseen));
if (filter.SubjectContains is not null)
criterions.Add(Expression.Subject(filter.SubjectContains));
if (filter.SenderContains is not null)
criterions.Add(Expression.From(filter.SenderContains));
if (filter.RecipientContains is not null)
criterions.Add(Expression.To(filter.RecipientContains));
if (filter.BodyContains is not null)
criterions.Add(Expression.Body(filter.BodyContains));
if (filter.Uid is UidFilter uidF)
{
if (uidF.Absolute is long exactUid)
criterions.Add(Expression.UID(new Limilabs.Client.IMAP.Range(exactUid, exactUid)));
else
{
long lo = uidF.Min ?? 1L;
long? hi = uidF.Max;
criterions.Add(Expression.UID(new Limilabs.Client.IMAP.Range(lo, hi)));
}
}
if (filter.Date is DateFilter dateF)
{
if (dateF.After is DateTime after)
@@ -81,14 +55,11 @@ public class LimilabsImapEmailService(
if (filter.SortOrder == MailSortOrder.NewestFirst)
uids.Reverse();
if (filter.MaxCount is int maxCount && maxCount > 0 && uids.Count > maxCount)
uids = [.. uids.Take(maxCount)];
#endregion
if (uids.Count == 0)
return [];
var results = new List<ReceivedEmailContext>(uids.Count);
foreach (var uid in uids)
@@ -97,7 +68,6 @@ public class LimilabsImapEmailService(
try
{
#region Read email
var email = await Cache.GetOrCreateAsync(
CacheKeyPrefix + uid,
@@ -105,6 +75,7 @@ public class LimilabsImapEmailService(
{
var eml = await imap.GetMessageByUIDAsync(uid, cancellationToken);
var mail = new MailBuilder().CreateFromEml(eml);
var flags = await imap.GetFlagsByUIDAsync(uid, cancellationToken);
var attachments = new List<EmailAttachmentContext>();
@@ -142,19 +113,53 @@ public class LimilabsImapEmailService(
TextBody = mail.Text ?? string.Empty,
HtmlBody = mail.Html ?? string.Empty,
Date = mail.Date ?? DateTime.MinValue,
IsSeen = flags.Contains(Flag.Seen),
Attachments = attachments,
};
});
#endregion Read email
if(email is not null)
if (email is null)
continue;
if (filter.UnseenOnly && email.IsSeen)
continue;
if (filter.SubjectContains is string subject &&
!email.Subject.Contains(subject, StringComparison.OrdinalIgnoreCase))
continue;
if (filter.SenderContains is string sender &&
!email.From.Contains(sender, StringComparison.OrdinalIgnoreCase))
continue;
if (filter.RecipientContains is string recipient &&
!email.To.Any(t => t.Contains(recipient, StringComparison.OrdinalIgnoreCase)) &&
!email.Cc.Any(c => c.Contains(recipient, StringComparison.OrdinalIgnoreCase)))
continue;
if (filter.BodyContains is string body &&
!email.TextBody.Contains(body, StringComparison.OrdinalIgnoreCase) &&
!email.HtmlBody.Contains(body, StringComparison.OrdinalIgnoreCase))
continue;
if (filter.Uid is UidFilter uidF)
{
if (filter.WithAttachments)
results.Add(email);
else
results.Add(email with { Attachments = [] });
if (uidF.Absolute is long exactUid && email.Uid != exactUid)
continue;
if (uidF.Min is long min && email.Uid < min)
continue;
if (uidF.Max is long max && email.Uid > max)
continue;
}
if (filter.WithAttachments)
results.Add(email);
else
results.Add(email with { Attachments = [] });
}
catch (Exception ex)
{
@@ -165,6 +170,10 @@ public class LimilabsImapEmailService(
}
await imap.CloseAsync(cancellationToken);
if (filter.MaxCount is int maxCount && maxCount > 0 && results.Count > maxCount)
return results.Take(maxCount);
return results;
}
catch (Limilabs.Client.ServerException ex)