How to search IMAP in .NET
One of many advantages IMAP protocol has over POP3 protocol is the ability to search.
There are several ways of performing search using Mail.dll .NET IMAP library:
- Search(Flag) – for common flag searches (seen, unseen, …).
- SimpleImapQuery – easy one object query, where all conditions are joined with an AND operator.
- Expression syntax – most advanced, allows using AND and OR operators and sorting.
IMAP search is done entirely on the server side, which means that it’s fast and doesn’t require Mail.dll client to download much data over the network.
Installation
The easiest way to install Mail.dll IMAP client for .NET is to download it from nuget via Package Manager:
PM> Install-Package Mail.dll
Alternatively you can download Mail.dll directly from our website.
Connect to IMAP
Let’s start with the basics: we’ll connect to the IMAP server in .NET app and authenticate:
// C# code:
using (Imap imap = new Imap())
{
imap.ConnectSSL("imap.example.com");
imap.UseBestLogin("user", "password");
imap.SelectInbox();
// Search code goes here
imap.Close();
}
' VB.NET code:
Using imap As New Imap()
imap.ConnectSSL("imap.example.com")
imap.UseBestLogin("user", "password")
imap.SelectInbox()
' Search code here
imap.Close()
End Using
When using Gmail you can use application passwords, with Office 365 you’ll need to use OAuth 2.0 to authenticate.
Mail.dll fully supports OAuth 2.0 for authentication, you can find OAuth2 samples for Office365 and Gmail on the Mail.dll samples page.
Search(Flag)
Now, let’s look at the search code. The first and the simplest way to search is by using Imap.Search(Flag) method. This sample below finds all unseen email messages (those that have \UNSEEN flag).
// C#
List<long> uidList = imap.Search(Flag.Unseen);
// now download each message and get the subject
foreach (long uid in uidList)
{
IMail message = new MailBuilder()
.CreateFromEml(imap.GetMessageByUID(uid));
string subject = message.Subject;
}
' VB.NET
Dim uidList As List(Of Long) = imap.Search(Flag.Unseen)
' now download each message and get the subject
For Each uid As Long In uidList
Dim message As IMail = New MailBuilder()_
.CreateFromEml(imap.GetMessageByUID(uid))
Dim subject As String = message.Subject
Next
SimpleImapQuery
Second approach is to use an IMAP query object. The sample below searches for all unseen emails with a certain subject. All non-null SimpleImapQuery properties are combined using and operator.
// C#
SimpleImapQuery query = new SimpleImapQuery();
query.Subject = "subject to search";
query.Unseen = true;
List<long> uids = imap.Search(query);
' VB.NET
Dim query As New SimpleImapQuery()
query.Subject = "subject to search"
query.Unseen = True
Dim uids As List(Of Long) = imap.Search(query)
Expression syntax
Finally, the most advanced search option using Expression class. You can use AND, OR and NOT operators in your IMAP search.
Note that Mail.dll fully encapsulates IMAP search syntax, with easy to use and very readable .NET classes:
// C#
List<long> uids = imap.Search().Where(
Expression.And(
Expression.Not(Expression.Subject("subject not to search")),
Expression.HasFlag(Flag.Unseen)));
' VB.NET
Dim uids As List(Of Long) = imap.Search().Where(_
Expression.[And](_
Expression.[Not](Expression.Subject("subject not to search")),_
Expression.HasFlag(Flag.Unseen)))
Expression syntax with sorting
Expression search syntax also allows sorting (defined in RFC 5256).
This feature is not available for every IMAP server: you need to check if your IMAP server supports ImapExtension.Sort extension first.
// C#
List<long> uids = imap.Search()
.Where(Expression.And(
Expression.Not(Expression.Subject("subject not to search")),
Expression.HasFlag(Flag.Unseen)))
.Sort(SortBy.Multiple(
SortBy.Date(),
SortBy.Subject()));
' VB.NET
Dim uids As List(Of Long) = imap.Search() _
.Where(Expression.[And]( _
Expression.[Not](Expression.Subject("subject not to search")), _
Expression.HasFlag(Flag.Unseen))) _
.Sort(SortBy.Multiple( _
SortBy.[Date](), _
SortBy.Subject()))
)
Notice the neat trick in Mail.dll .NET client, that allows casting FluentSearch class, received from imap.Search() method, to List<longs>:
public static implicit operator List<long>(FluentSearch search)
{
return search.GetList();
}
We tend to use it very often for builder objects used in our unit tests.
Suggested reading
If you like it just give it a try and download it at: Mail.dll .NET IMAP component
Get Mail.dll
March 30th, 2014 at 12:29
Can you search by message id? I see you have a header option to search by but not sure how to use it.
March 30th, 2014 at 13:31
Yes, you can search by message-id header:
March 30th, 2014 at 15:52
Worked perfect!!
February 8th, 2015 at 22:24
Can you search the Body? I tried Expression.Body(text to search for) but I get an unhandled error.
February 8th, 2015 at 23:13
@Peter
Yes, you can search the body:
What kind of exception are you getting?
What is the message?
What is the stack trace?
Can you prepare a log file (http://www.limilabs.com/blog/logging-in-mail-dll)?
What server are you using?
Are you using any special characters?
February 8th, 2015 at 23:20
I am using Windows Server 2008 R2, IIS 7.5 with .Net 4.0 (c#).
I can prepare a log file tomorrow morning – the only message I got was an unhandled error as i did not have logging turned on.
I am passing a string with standard HTML formatting to search on so likely I do have some special characters in the string (it is pretty long). I can test with a simpler string in the morning as well.
February 9th, 2015 at 13:35
@Peter
You said you are using pretty long strings.
Most likely the problem is with CR LF characters.
Currently you can not use those characters in searches. Sorry.We’ll try to address this issue in next release.
February 9th, 2015 at 13:42
Good Morning,
It seems like the Expression.Body statement error’s out when the string for the search criteria includes an apostrophe. There may be other characters as well.
It work’s fine when I pass a short string with only alpha characters. […]
February 9th, 2015 at 14:51
@Peter
Unfortunatelly this is a Gmail bug. There is nothing we can do about it.
Gmail has very similar problem with national characters.
February 9th, 2015 at 17:18
No worries Paul – I can work around this requirement (it is likely better not to search on the Body text anyway for the purposes that I was considering doing it).
Thanks for your help.
February 22nd, 2015 at 16:27
Mail.dll was updated today and now supports any characters in the search, including CR LF.
Mail.dll now uses a bit different IMAP server communication model and we have been able to workaround this Gmail bug. From now on national characters should work correctly in Gmail searches
April 20th, 2015 at 19:56
I want to only retrieve a list of emails via IMAP in date range specified (based on the date the email was sent). I have done quite a lot of searching on this site and online and can’t find an example for how to do this. Does anyone have a sample to get me started or even point me to the method or class that I should be using to do this?
April 21st, 2015 at 10:19
Ben,
Unfortunately IMAP protocol does not have such feature.)What can you do is to use Imap.GetEnvelope or GetMessageInfo methods to download informations about all emails (it’s relatively fast) as described here:http://www.limilabs.com/blog/get-email-information-from-imap-fast
Envelope has a Date field that you can use (it corresponds to email’s Date header(See Ben comment below)
April 29th, 2015 at 21:35
Hmmm…
I spent a couple of days now looking at this and unfortunately, I believe you are incorrect. When I do this code with imap:
DateTime dateBegin = DateTime.Now.AddDays(-30);
List listOfUids = imap.Search(Expression.SentSince(dateBegin);
This works and returns back the correct number of Uid’s within that range and is still very quick.
Maybe I asked my question incorrectly?
May 1st, 2015 at 10:19
@Ben,
You are correct.
I totally forgot about Expression.Since and Expression.SentSince.
August 18th, 2015 at 14:49
I’m trying a filter criteria based on the Subject as well as From address with an Expression.OR condition and it always returns only 160 results…Is there a limitation with the trial version?
August 18th, 2015 at 18:11
@Kris
Most likley you are using Yahoo as your email provider.
It seems Yahoo is limiting the search result (for queries that search subject, body) to the newest 160 records.
It also seems that there is no way to get to the previous records using IMAP search.
It’s definitively Yahoo bug, and currently I don’t see a way to workaround it.
September 15th, 2015 at 12:24
Is it possible to nest multiple or expressions, to add more from-criteria to something like
?
in other words: where sentsince>20110901 && (from ==”a.com” || from ==”b.com”|| from ==”c.com”) etc etc
Thanks,
knut
September 15th, 2015 at 18:54
@Knut
Yes, it should work exactly like you put it (I just applied some formatting).
September 16th, 2015 at 08:30
Guess I’m getting lost in all the brackets… – I need to put an Expression.Or first?
September 17th, 2015 at 06:54
@Knut,
The expression you provided works exactlly like you want:
sentsince>2011/09/01 && (from == “a.com” || from == “b.com”)
November 6th, 2015 at 10:33
When I search for Expression.From(“first name last name”) – it finds the mail.
When I search for Expression.From(“name@domain.com”) – it does not find the mail.
So, it appears to only search the display name of the from text, not the from email address.
Is there any way to search for the from email address?
November 8th, 2015 at 12:54
@Gonzo
The search is done entirely on the server side.
If the server implements search functionality incorrectly there is not much we can do.
Could you prepare a log file for us, so we can make sure that Mail.dll generates correct search query?
December 2nd, 2015 at 05:53
hi,
I am a web developer who is trying to implement a web mail as a part of the project that i am working on. it requires synchronous the local cache and imap server. would you please let me know how would I search mailbox by uid? (i need to search uid greater than a certain value) so that i can only download the email from server which haven’t been downloaded yet.
many thanks
best regards
Louie
December 2nd, 2015 at 11:04
@Louie
You can use Expression.UID method.
It allows you to select a range of uids you are interested in.
To search uids greater that a certain value:
To search uids in specified range (from 55 included to 135 included):
December 5th, 2015 at 02:19
hi
I have just tried to client.Search().Where(Expression.UID(Range.From(100))); it still return me the email with biggest uid on server (25). however, when i use rang.creat(26,100), it give me the correct result (no emails found).
December 6th, 2015 at 19:13
@Louie,
I’m afraid that this may be a server bug (the search is done entirely on the IMAP server side).
September 11th, 2016 at 08:44
Hi, there is a small problem i am facing..i am using your fantastic product to retrieve from mails from ms outlook. when I use,
List uids = imap.Search(Flag.New);
i can access new recieved mails..but if i just open outlook and try that command, it returns 0, also, i tried seen, unseen and All also..but returns 0 but i can see unread n read mails in my inbox.. why is this?? please help..
September 11th, 2016 at 12:08
@Hasitha
Search is done always on the server side. Exchange can decide that a message is no longer \NEW or \UNSEEN when it has been downloaded by Outlook.
You can remember the last uid you have downloaded to be 100% sure you get all new messages.
It is a good solution in those cases when multiple users/programs access single mailbox/folder.
September 12th, 2016 at 04:30
okey, thank you very much for you help.. i will try that out 🙂
March 1st, 2017 at 13:06
I am using the SimpleImapQuery to filter the email From and To but how can I also limit the search for 5 days etc.
March 4th, 2017 at 13:13
@Harold Garcia
You can’t. Consider using searching using Expression syntax.
Remember that you can use SimpleImapQuery object as part of your Expression query.
October 23rd, 2017 at 21:49
Search with subject search criteria containing Unicode fails with exception “Tried to read a line. No data received.”
October 24th, 2017 at 08:03
@Elana V,
Please make sure you are using the latest version (http://www.limilabs.com/static/mail/ReleaseNotes.txt).
Mail.dll correctly escapes all unicode characters, but there are many IMAP servers out there, that act incorrectly and violate IMAP protocol. “Tried to read a line. No data received.” error means that the server suddenly disconnected or failed to send anything.
What server are you using? Can you turn on logging (http://www.limilabs.com/blog/logging-in-mail-dll) and contact us directly (http://www.limilabs.com/support)?
October 24th, 2017 at 20:09
Thanks for the fast reply, this helped a lot!
I sent all requested stuff to your support (along with logs and tech details).
The server is Yahoo, imap.mail.yahoo.com.
Today I got
[CLIENTBUG] UID SEARCH Command arguments invalid.
for SUBJECT search with “письмо” literal (Cyrillic).
This is exactly the same error which we got in our product before to try yours until the issue will be resolved. Seems Yahoo IMAP server bug for Unicode literals. ASCII works ok, this is only about Unicode literals.
Seems Yahoo IMAP bug. Definitely this search worked in past.
Again thanks!
October 24th, 2017 at 20:31
@Elena V,
This definitely Yahoo’s bug. Yahoo search doesn’t work with national (unicode) characters.
As far as I remember, previously Yahoo disconnected when search phrase included unicode characters; now it sends BAD [CLIENTBUG] UID SEARCH Command arguments invalid”, which is ridiculous as this is server side problem.
As a side note: it seems to me that they updated their server recently and now it fails to create/select folders with unicode characters.