Skip to content

Commit 7db2280

Browse files
committed
IMailFolderClient.SearchAsync tagged with "Consider using IMailReader.Query() instead."
1 parent 3aa0808 commit 7db2280

File tree

4 files changed

+61
-31
lines changed

4 files changed

+61
-31
lines changed

samples/WorkerServiceExample/Worker.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ private async Task GetMessageSummaryRepliesAsync(CancellationToken cancellationT
3434
{
3535
var stopwatch = Stopwatch.StartNew();
3636
var messageSummaries = await _imapReceiver.ReadMail
37-
.Skip(31).Take(1)
38-
.Items(MessageSummaryItems.Envelope)
39-
//.Query(SearchQuery.NotSeen)
37+
.Skip(31).Take(1).Items(MessageSummaryItems.Envelope)
4038
.GetMessageSummariesAsync(cancellationToken);
4139
stopwatch.Stop();
4240
_logger.LogInformation($"Received {messageSummaries.Count} email(s) in {stopwatch.Elapsed.TotalSeconds:n1}s: {messageSummaries.Select(m => m.UniqueId).ToEnumeratedString()}.");
@@ -52,6 +50,18 @@ private async Task GetMessageSummaryRepliesAsync(CancellationToken cancellationT
5250
}
5351
}
5452

53+
private async Task GetMimeMessageRepliesAsync(CancellationToken cancellationToken = default)
54+
{
55+
var stopwatch = Stopwatch.StartNew();
56+
var mimeMessages = await _imapReceiver.ReadMail
57+
.Take(1).Query(SearchQuery.NotSeen)
58+
.GetMimeMessagesAsync(cancellationToken);
59+
stopwatch.Stop();
60+
_logger.LogInformation($"Received {mimeMessages.Count} email(s) in {stopwatch.Elapsed.TotalSeconds:n1}s.");
61+
var mimeReply = mimeMessages.Single().GetReplyMessage("Reply here.", addRecipients: false, includeMessageId: true, cancellationToken: cancellationToken);
62+
_logger.LogInformation($"Reply: \r\n{mimeReply.HtmlBody}");
63+
}
64+
5565
private async Task ReceiveAsync(CancellationToken cancellationToken = default)
5666
{
5767
var stopwatch = Stopwatch.StartNew();
@@ -65,7 +75,7 @@ private async Task QueryAsync(CancellationToken cancellationToken = default)
6575
{
6676
var stopwatch = Stopwatch.StartNew();
6777
var messageSummaries = await _imapReceiver.ReadMail.Query(MailFolderReader.QueryMessageId(""))
68-
.GetMessageSummariesAsync(MessageSummaryItems.Envelope, cancellationToken);
78+
.GetMessageSummariesAsync(MailFolderReader.CoreMessageItems, cancellationToken);
6979
stopwatch.Stop();
7080
_logger.LogInformation($"Received {messageSummaries.Count} email(s) in {stopwatch.Elapsed.TotalSeconds:n1}s: {messageSummaries.Select(m => m.UniqueId).ToEnumeratedString()}.");
7181
}

source/MailKitSimplified.Receiver/Abstractions/IMailFolderClient.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public interface IMailFolderClient : IAsyncDisposable, IDisposable
2323
/// <param name="searchQuery">Mail folder search query.</param>
2424
/// <param name="cancellationToken">Cancellation token.</param>
2525
/// <returns>The first 250 <see cref="UniqueId"/>s.</returns>
26+
[Obsolete("Consider using IMailReader.Query() instead.")]
2627
Task<IList<UniqueId>> SearchAsync(SearchQuery searchQuery, CancellationToken cancellationToken = default);
2728

2829
/// <summary>

source/MailKitSimplified.Receiver/Extensions/MimeMessageExtensions.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ public static class MimeMessageExtensions
2121
/// </summary>
2222
/// <param name="original">MimeMessage original to forward.</param>
2323
/// <param name="message">Forward message text/html body.</param>
24+
/// <param name="includeMessageId">Whether to quote the Message-ID or not.</param>
25+
/// <param name="cancellationToken">Cancellation token.</param>
2426
/// <returns>MimeMessage forward ready for From and To addresses.</returns>
25-
public static MimeMessage GetForwardMessage(this MimeMessage original, string message) =>
26-
original.GetMimeMessageResponse(FW, message, includeAttachments: true);
27+
public static MimeMessage GetForwardMessage(this MimeMessage original, string message, bool includeMessageId = false, CancellationToken cancellationToken = default) =>
28+
original.GetMimeMessageResponse(FW, message, includeAttachments: true, includeMessageId: includeMessageId, cancellationToken: cancellationToken);
2729

2830
/// <summary>
2931
/// Get a MimeMessage reply from a MimeMessage original.
@@ -32,16 +34,18 @@ public static MimeMessage GetForwardMessage(this MimeMessage original, string me
3234
/// <param name="message">Reply message text/html body.</param>
3335
/// <param name="addRecipients">Whether to reply to sender or not.</param>
3436
/// <param name="replyToAll">Whether to reply to all original recipients or not.</param>
37+
/// <param name="includeMessageId">Whether to quote the Message-ID or not.</param>
38+
/// <param name="cancellationToken">Cancellation token.</param>
3539
/// <returns>MimeMessage reply ready for From (and To) addresses.</returns>
36-
public static MimeMessage GetReplyMessage(this MimeMessage original, string message, bool addRecipients = true, bool replyToAll = false)
40+
public static MimeMessage GetReplyMessage(this MimeMessage original, string message, bool addRecipients = true, bool replyToAll = false, bool includeMessageId = false, CancellationToken cancellationToken = default)
3741
{
38-
var mimeMessage = original.GetMimeMessageResponse(RE, message, includeAttachments: false);
42+
var mimeMessage = original.GetMimeMessageResponse(RE, message, includeAttachments: false, includeMessageId: includeMessageId, cancellationToken: cancellationToken);
3943
if (addRecipients)
4044
mimeMessage.To.AddRange(original.BuildReplyAddresses(replyToAll));
4145
return mimeMessage;
4246
}
4347

44-
internal static MimeMessage GetMimeMessageResponse(this MimeMessage original, string subjectPrefix = "", string bodyPrefix = "", bool includeAttachments = true, bool includeEmbedded = true)
48+
internal static MimeMessage GetMimeMessageResponse(this MimeMessage original, string subjectPrefix = "", string bodyPrefix = "", bool includeAttachments = true, bool includeEmbedded = true, bool includeMessageId = false, bool forceHtml = true, CancellationToken cancellationToken = default)
4549
{
4650
if (original == null)
4751
throw new ArgumentNullException(nameof(original));
@@ -56,7 +60,7 @@ internal static MimeMessage GetMimeMessageResponse(this MimeMessage original, st
5660
mimeMessage.AddMessageIdReferences(original);
5761

5862
// Quote the original message text with optional linked resources and attachments
59-
mimeMessage.Body = original.BuildMessageBody(bodyPrefix, includeAttachments, includeEmbedded);
63+
mimeMessage.Body = original.BuildMessageBody(bodyPrefix, includeAttachments, includeEmbedded, includeMessageId, forceHtml, cancellationToken);
6064

6165
return mimeMessage;
6266
}
@@ -143,13 +147,13 @@ internal static BodyBuilder GetBuilder(this MimeMessage original, bool includeAt
143147
return builder;
144148
}
145149

146-
internal static MimeEntity BuildMessageBody(this MimeMessage original, string prependText = "", bool includeAttachments = true, bool includeEmbedded = true, bool setHtml = true)
150+
internal static MimeEntity BuildMessageBody(this MimeMessage original, string prependText = "", bool includeAttachments = true, bool includeEmbedded = true, bool includeMessageId = false, bool forceHtml = true, CancellationToken cancellationToken = default)
147151
{
148152
if (original == null)
149153
return new TextPart();
150154
MimeEntity mimeBody;
151-
bool isHtml = setHtml || original.HtmlBody != null;
152-
var replyText = original.QuoteForReply(prependText);
155+
bool isHtml = forceHtml || original.HtmlBody != null;
156+
var replyText = original.QuoteForReply(prependText, includeMessageId, cancellationToken);
153157
if (includeEmbedded || includeAttachments)
154158
{
155159
var builder = original.GetBuilder(includeAttachments, includeEmbedded);

source/MailKitSimplified.Receiver/Services/MailFolderReader.cs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using System.Collections.Generic;
99
using MailKitSimplified.Receiver.Abstractions;
1010
using MailKitSimplified.Receiver.Extensions;
11+
using Microsoft.Extensions.Logging;
12+
using Microsoft.Extensions.Logging.Abstractions;
1113

1214
namespace MailKitSimplified.Receiver.Services
1315
{
@@ -59,13 +61,16 @@ public static SearchQuery QueryMessageId(string messageId, bool addAngleBrackets
5961
private int _take = _all;
6062
private bool _continueTake = false;
6163
private static readonly int _all = -1;
64+
private static readonly int _queryAmount = 250;
6265
private SearchQuery _searchQuery = _queryAll;
6366
private static readonly SearchQuery _queryAll = SearchQuery.All;
6467
private MessageSummaryItems _messageSummaryItems = MessageSummaryItems.Envelope;
68+
private readonly ILogger _logger;
6569
private readonly IImapReceiver _imapReceiver;
6670

67-
public MailFolderReader(IImapReceiver imapReceiver)
71+
public MailFolderReader(IImapReceiver imapReceiver, ILogger<MailFolderReader> logger = null)
6872
{
73+
_logger = logger ?? NullLogger<MailFolderReader>.Instance;
6974
_imapReceiver = imapReceiver ?? throw new ArgumentNullException(nameof(imapReceiver));
7075
}
7176

@@ -98,22 +103,40 @@ public IMailReader Items(MessageSummaryItems messageSummaryItems)
98103
return this;
99104
}
100105

101-
public async Task<IList<IMessageSummary>> GetMessageSummariesAsync(MessageSummaryItems filter, CancellationToken cancellationToken = default)
106+
private async Task<IMailFolder> OpenMailFolderAsync(CancellationToken cancellationToken = default)
102107
{
103108
if (_take == 0)
104-
return Array.Empty<IMessageSummary>();
109+
return null;
105110
var mailFolder = await _imapReceiver.ConnectMailFolderAsync(cancellationToken).ConfigureAwait(false);
106111
_ = await mailFolder.OpenAsync(FolderAccess.ReadOnly, cancellationToken).ConfigureAwait(false);
107-
if (_skip >= mailFolder.Count)
112+
if (_skip >= mailFolder.Count || (_skip > _queryAmount && _searchQuery != _queryAll))
108113
{
114+
if (_skip < mailFolder.Count)
115+
{
116+
_logger.LogWarning($"Skip({_skip}) limited to mail folder count of {mailFolder.Count}.");
117+
if (_continueTake)
118+
_skip = mailFolder.Count;
119+
}
120+
else
121+
_logger.LogWarning($"Skip({_skip}) exceeded SearchQuery limit of 250 results.");
109122
await mailFolder.CloseAsync(false, CancellationToken.None).ConfigureAwait(false);
110-
return Array.Empty<IMessageSummary>();
123+
return null;
111124
}
125+
return mailFolder;
126+
}
127+
128+
public async Task<IList<IMessageSummary>> GetMessageSummariesAsync(MessageSummaryItems filter, CancellationToken cancellationToken = default)
129+
{
130+
var mailFolder = await OpenMailFolderAsync(cancellationToken).ConfigureAwait(false);
131+
if (mailFolder == null)
132+
return Array.Empty<IMessageSummary>();
112133

113134
IList<IMessageSummary> filteredSummaries;
114135
filter |= MessageSummaryItems.UniqueId;
115136
if (_searchQuery != _queryAll)
116137
{
138+
if (_take > _queryAmount)
139+
_logger.LogWarning($"Take({_take}) limited by SearchQuery to 250 results.");
117140
var uniqueIds = await mailFolder.SearchAsync(_searchQuery, cancellationToken).ConfigureAwait(false);
118141
var descendingUids = uniqueIds.OrderByDescending(u => u.Id).Skip(_skip);
119142
var filteredUids = _take == _all ? descendingUids : descendingUids.Take(_take);
@@ -127,12 +150,7 @@ public async Task<IList<IMessageSummary>> GetMessageSummariesAsync(MessageSummar
127150
filteredSummaries = await mailFolder.FetchAsync(_skip, endIndex, filter, cancellationToken).ConfigureAwait(false);
128151
}
129152
if (_continueTake && _take > 0)
130-
{
131-
if (_skip < mailFolder.Count)
132-
_skip += _take;
133-
else
134-
_skip = mailFolder.Count;
135-
}
153+
_skip += _take;
136154
await mailFolder.CloseAsync(false, CancellationToken.None).ConfigureAwait(false);
137155

138156
return filteredSummaries;
@@ -145,18 +163,15 @@ public async Task<IList<MimeMessage>> GetMimeMessagesAsync(CancellationToken can
145163
{
146164
if (_take == 0)
147165
return Array.Empty<MimeMessage>();
148-
var mailFolder = await _imapReceiver.ConnectMailFolderAsync(cancellationToken).ConfigureAwait(false);
149-
_ = await mailFolder.OpenAsync(FolderAccess.ReadOnly, cancellationToken).ConfigureAwait(false);
150-
if (_skip >= mailFolder.Count)
151-
{
152-
await mailFolder.CloseAsync(false, CancellationToken.None).ConfigureAwait(false);
166+
var mailFolder = await OpenMailFolderAsync(cancellationToken).ConfigureAwait(false);
167+
if (mailFolder == null)
153168
return Array.Empty<MimeMessage>();
154-
}
155169

156-
_ = await mailFolder.OpenAsync(FolderAccess.ReadOnly, cancellationToken).ConfigureAwait(false);
157170
var mimeMessages = new List<MimeMessage>();
158171
if (_take == _all || _searchQuery != _queryAll)
159172
{
173+
if (_take > _queryAmount)
174+
_logger.LogWarning($"Take({_take}) limited by SearchQuery to 250 results.");
160175
var uniqueIds = await mailFolder.SearchAsync(_searchQuery, cancellationToken).ConfigureAwait(false);
161176
var descendingUids = uniqueIds.OrderByDescending(u => u.Id).Skip(_skip);
162177
var filteredUids = _take == _all ? descendingUids : descendingUids.Take(_take);

0 commit comments

Comments
 (0)