Add support for optional email attachments fetching
Introduced a `withAttachments` parameter to the `FetchEmailsAsync` method in `IImapEmailService` and related layers, allowing callers to include or exclude attachment data when fetching emails. Updated `FetchEmailsQuery` and `FetchEmailsQueryHandler` to propagate this parameter. Refactored `LimilabsImapEmailService` to conditionally process attachments and inline visuals based on the `withAttachments` flag, improving performance when attachments are not required. Replaced `Flag.Unseen` with `Expression.HasFlag(Flag.Unseen)` for better criteria handling. Cleaned up attachment-processing logic for improved readability and maintainability.
This commit is contained in:
@@ -13,10 +13,12 @@ public interface IImapEmailService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="account">Account whose IMAP settings will be used.</param>
|
/// <param name="account">Account whose IMAP settings will be used.</param>
|
||||||
/// <param name="filter">Filter to apply when fetching emails.</param>
|
/// <param name="filter">Filter to apply when fetching emails.</param>
|
||||||
|
/// <param name="withAttachments">When <see langword="true"/>, attachment data is included in the results; otherwise attachments are omitted. Defaults to <see langword="false"/>.</param>
|
||||||
/// <param name="cancellationToken">Cancellation token.</param>
|
/// <param name="cancellationToken">Cancellation token.</param>
|
||||||
Task<IEnumerable<ReceivedEmailContext>> FetchEmailsAsync(
|
Task<IEnumerable<ReceivedEmailContext>> FetchEmailsAsync(
|
||||||
EmailAccountDto account,
|
EmailAccountDto account,
|
||||||
MailSearchFilter filter,
|
MailSearchFilter filter,
|
||||||
|
bool withAttachments = false,
|
||||||
CancellationToken cancellationToken = default);
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ public record FetchEmailsQuery : IRequest<IEnumerable<ReceivedEmailContext>>
|
|||||||
/// Mail query used to filter and limit the emails retrieved.
|
/// Mail query used to filter and limit the emails retrieved.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MailSearchFilter Mail { get; init; } = new();
|
public MailSearchFilter Mail { get; init; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When <see langword="true"/>, attachment data is included in the results; otherwise attachments are omitted.
|
||||||
|
/// Defaults to <see langword="false"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool WithAttachments { get; init; } = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FetchEmailsQueryHandler(
|
public class FetchEmailsQueryHandler(
|
||||||
@@ -40,6 +46,7 @@ public class FetchEmailsQueryHandler(
|
|||||||
return await ImapService.FetchEmailsAsync(
|
return await ImapService.FetchEmailsAsync(
|
||||||
account,
|
account,
|
||||||
request.Mail,
|
request.Mail,
|
||||||
|
request.WithAttachments,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public class LimilabsImapEmailService(
|
|||||||
public async Task<IEnumerable<ReceivedEmailContext>> FetchEmailsAsync(
|
public async Task<IEnumerable<ReceivedEmailContext>> FetchEmailsAsync(
|
||||||
EmailAccountDto account,
|
EmailAccountDto account,
|
||||||
MailSearchFilter filter,
|
MailSearchFilter filter,
|
||||||
|
bool withAttachments = false,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
using var imap = new Imap();
|
using var imap = new Imap();
|
||||||
@@ -38,7 +39,7 @@ public class LimilabsImapEmailService(
|
|||||||
List<ICriterion> criterions = [];
|
List<ICriterion> criterions = [];
|
||||||
|
|
||||||
if (filter.UnseenOnly)
|
if (filter.UnseenOnly)
|
||||||
criterions.Add((ICriterion)Flag.Unseen);
|
criterions.Add(Expression.HasFlag(Flag.Unseen));
|
||||||
|
|
||||||
if (filter.SubjectContains is not null)
|
if (filter.SubjectContains is not null)
|
||||||
criterions.Add(Expression.Subject(filter.SubjectContains));
|
criterions.Add(Expression.Subject(filter.SubjectContains));
|
||||||
@@ -103,7 +104,7 @@ public class LimilabsImapEmailService(
|
|||||||
if (filter.HasAttachments && mail.Attachments.Count == 0 && mail.Visuals.Count == 0)
|
if (filter.HasAttachments && mail.Attachments.Count == 0 && mail.Visuals.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
results.Add(MapToContext(uid, mail, flags));
|
results.Add(MapToContext(uid, mail, flags, withAttachments));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -179,32 +180,35 @@ public class LimilabsImapEmailService(
|
|||||||
await imap.SelectAsync(folder);
|
await imap.SelectAsync(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReceivedEmailContext MapToContext(long uid, IMail mail, List<Flag> flags)
|
private static ReceivedEmailContext MapToContext(long uid, IMail mail, List<Flag> flags, bool withAttachments = false)
|
||||||
{
|
{
|
||||||
var attachments = new List<EmailAttachmentContext>();
|
var attachments = new List<EmailAttachmentContext>();
|
||||||
|
|
||||||
foreach (var att in mail.Attachments)
|
if (withAttachments)
|
||||||
{
|
{
|
||||||
attachments.Add(new EmailAttachmentContext
|
foreach (var att in mail.Attachments)
|
||||||
{
|
{
|
||||||
FileName = att.FileName ?? "attachment",
|
attachments.Add(new EmailAttachmentContext
|
||||||
Content = att.Data,
|
{
|
||||||
ContentType = att.ContentType?.ToString() ?? "application/octet-stream",
|
FileName = att.FileName ?? "attachment",
|
||||||
IsInline = false,
|
Content = att.Data,
|
||||||
ContentId = att.ContentId
|
ContentType = att.ContentType?.ToString() ?? "application/octet-stream",
|
||||||
});
|
IsInline = false,
|
||||||
}
|
ContentId = att.ContentId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var vis in mail.Visuals)
|
foreach (var vis in mail.Visuals)
|
||||||
{
|
|
||||||
attachments.Add(new EmailAttachmentContext
|
|
||||||
{
|
{
|
||||||
FileName = vis.FileName ?? "inline",
|
attachments.Add(new EmailAttachmentContext
|
||||||
Content = vis.Data,
|
{
|
||||||
ContentType = vis.ContentType?.ToString() ?? "application/octet-stream",
|
FileName = vis.FileName ?? "inline",
|
||||||
IsInline = true,
|
Content = vis.Data,
|
||||||
ContentId = vis.ContentId
|
ContentType = vis.ContentType?.ToString() ?? "application/octet-stream",
|
||||||
});
|
IsInline = true,
|
||||||
|
ContentId = vis.ContentId
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ReceivedEmailContext
|
return new ReceivedEmailContext
|
||||||
|
|||||||
Reference in New Issue
Block a user