{"id":3265,"date":"2012-07-15T23:36:17","date_gmt":"2012-07-15T21:36:17","guid":{"rendered":"http:\/\/www.limilabs.com\/blog\/?p=3265"},"modified":"2019-05-10T17:42:46","modified_gmt":"2019-05-10T15:42:46","slug":"get-new-emails-using-imap","status":"publish","type":"post","link":"https:\/\/www.limilabs.com\/blog\/get-new-emails-using-imap","title":{"rendered":"Get new emails using IMAP"},"content":{"rendered":"<p>This article describes <strong>how to receive new email messages<\/strong> using Mail.dll <a href=\"\/mail\">.NET IMAP library<\/a>.<\/p>\n<p>In many situations you can relay on IMAP server to keep track which messages are unseen and just <a href=\"\/blog\/receive-unseen-emails-using-imap\">download unseen messages from IMAP server<\/a>. However when user interaction or other program connecting and downloading emails may remove UNSEEN flag from the message, you may be forced to manually <strong>track which messages where already downloaded and which are new<\/strong>.<\/p>\n<p>You could of course download all Unique IDs (UIDs) of the messages that are in the mailbox, but there is a more elegant way.<\/p>\n<p><a href=\"\/blog\/unique-id-in-imap-protocol\">Unique IDs (UIDs) in IMAP<\/a> have some very interesting feature &#8211; they <strong>are assigned in incremental order<\/strong>. This means that new messages always have higher UIDs than old ones.<\/p>\n<p>This is the reason you only need to remember the newest (greatest) UID that was downloaded during a previous session (connection to the IMAP server). On the next session you need to <a href=\"\/blog\/how-to-search-imap-in-net\">search IMAP<\/a> for UIDs that are greater than the one remembered.<\/p>\n<p>First we need to load largest uid from the previous session and connect to the IMAP server. In this exmaple we select INBOX, but you can use <em>Select<\/em> method to select a different folder.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ C#\r\n\r\nlong? largestUID = LoadLargestFromPreviousRun();\r\n\r\nusing (Imap imap = new Imap ())\r\n{\r\n    imap.Connect(&quot;imap.example.com&quot;);  \/\/ or ConnectSSL for SSL\r\n    imap.UseBestLogin(&quot;user&quot;, &quot;password&quot;);\r\n\r\n    imap.SelectInbox();\r\n<\/pre>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n' VB.NET\r\n\r\nDim largestUID As System.Nullable(Of Long) = LoadLargestFromPreviousRun()\r\n\r\nUsing imap As New Imap ()\r\n    imap.Connect(&quot;imap.example.com&quot;)   ' or ConnectSSL for SSL\r\n    imap.UseBestLogin(&quot;user&quot;, &quot;password&quot;)\r\n\r\n    imap.SelectInbox()\r\n<\/pre>\n<p>Next step is to select folder, <strong>download unique ids (UIDs) larger than <em>largestUID<\/em><\/strong> value that was stored on the previous run. This way we obtain uids of the new emails.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ C#\r\n\r\nList&lt;long&gt; uids;\r\nif (largestUID == null)\r\n{\r\n    uids = imap.GetAll();\r\n}\r\nelse\r\n{\r\n    uids = imap.Search().Where(\r\n        Expression.UID(Range.From(largestUID.Value)));\r\n    uids.Remove(largestUID);\r\n}\r\n\r\n<\/pre>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n' VB.NET\r\n\r\nDim uids As List(Of Long)\r\nIf largestUID Is Nothing Then\r\n\tuids = imap.GetAll()\r\nElse\r\n\tuids = imap.Search().Where(Expression.UID(Range.From(largestUID.Value)))\r\n\tuids.Remove(largestUID)\r\nEnd If\r\n\r\n<\/pre>\n<p>You should note <em>uids.Remove<\/em> in the code above. It is used because <em>Range.From<\/em> creates a range of uids greater <strong>or equal<\/strong> to the specified value and * represents the largest value in the mailbox, so the largest uid is always included.<\/p>\n<p>Finally we&#8217;ll iterate through the UID list and use <em>GetMessageByUID<\/em> method to download each message from the server. You can use <em>MailBuilder <\/em>class to <strong>parse those email messages, extract attachments and process them anyway you like<\/strong>. The last step is to save the last UID that was processed:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ C#\r\n\r\nforeach (long uid in uids)\r\n{\r\n    var eml = imap.GetMessageByUID(uid);\r\n    IMail email = new MailBuilder().CreateFromEml(eml);\r\n\r\n    Console.WriteLine(email.Subject);\r\n    Console.WriteLine(email.Text);\r\n   \r\n    SaveLargestUID(uid.Value);\r\n}\r\n<\/pre>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n' VB.NET\r\n\r\nFor Each uid As Long In uids\r\n\tDim eml = imap.GetMessageByUID(uid)\r\n\tDim email As IMail = New MailBuilder().CreateFromEml(eml)\r\n\r\n\tConsole.WriteLine(email.Subject)\r\n\tConsole.WriteLine(email.Text)\r\n\r\n\tSaveLargestUID(uid.Value)\r\nNext\r\n<\/pre>\n<h2>SaveLargestUID, LoadLargest&#8230; methods<\/h2>\n<p>You need to write those methods on your own. They should save\/load largest uid from\/to your preferred storage (such as database, file, registry).<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ C#\r\n\r\nprivate void SaveLargestUID(long uid)\r\n{\r\n    \/\/ Your code that saves the uid.\r\n}\r\n\r\nprivate long  LoadLargestFromPreviousRun()\r\n{\r\n    \/\/ Your code that loads the largest uid (null on the first run).\r\n}\r\n<\/pre>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n' VB.NET\r\n\r\nPrivate Sub SaveLargestUID(uid As Long)\r\n    ' Your code that saves the uid.\r\nEnd Sub\r\n\r\nPrivate Function LoadLargestFromPreviousRun() As Long\r\n    ' Your code that loads the largest uid (null on the first run).\r\nEnd Sub\r\n<\/pre>\n<h2>UIDs across sessions &#8211; UIDValidity<\/h2>\n<p>It is advised for IMAP servers to not change UIDs between sessions. There are however situations when server <strong>may invalidate all UIDs that were in the mailbox<\/strong> previously.<\/p>\n<p>Consider a user that deletes a folder (mailbox) including all its messages and creates new one with exactly the same name. All uids that were downloaded previously are no longer valid &#8211; they simply don&#8217;t exist in this folder anymore.<\/p>\n<p>You can recognize such situation by comparing <em>FolderStatus.UIDValidity<\/em> value. If the <em>FolderStatus.UIDValidity <\/em> number hasn&#8217;t changed, then the UIDs are still valid. Below is the sample showing how to print <em>UIDValidity<\/em>:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ C#\r\n\r\nFolderStatus status = client.SelectInbox();\r\nConsole.WriteLine(status.UIDValidity);\r\n\r\n<\/pre>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n' VB.NET\r\n\r\nDim status As FolderStatus = client.SelectInbox()\r\nConsole.WriteLine(status.UIDValidity)\r\n<\/pre>\n<h2>Entire samples<\/h2>\n<p>Below you can find full samples in both C# and VB.NET:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ C#\r\n\r\nusing Limilabs.Mail;\r\nusing Limilabs.Client.IMAP;\r\n\r\ninternal class LastRun\r\n{\r\n    public long UIDValidity { get; set; }\r\n    public long LargestUID { get; set; }\r\n}\r\n\r\nprivate static void Main(string&#x5B;] args)\r\n{\r\n    LastRun last = LoadPreviousRun();\r\n\r\n    using (Imap imap = new Imap())\r\n    {\r\n        imap.Connect(&quot;imap.example.com&quot;); \/\/ or ConnectSSL for SSL\r\n        imap.UseBestLogin(&quot;user&quot;, &quot;password&quot;);\r\n\r\n        FolderStatus status = imap.SelectInbox();\r\n\r\n        List&lt;long&gt; uids;\r\n        if (last == null || last.UIDValidity != status.UIDValidity)\r\n        {\r\n            uids = imap.GetAll();\r\n        }\r\n        else\r\n        {\r\n            uids = imap.Search().Where(\r\n                Expression.UID(Range.From(last.LargestUID)));\r\n            uids.Remove(last.LargestUID);\r\n        }\r\n\r\n        foreach (long uid in uids)\r\n        {\r\n            var eml = imap.GetMessageByUID(uid);\r\n            IMail email = new MailBuilder()\r\n                .CreateFromEml(eml);\r\n\r\n            Console.WriteLine(email.Subject);\r\n            Console.WriteLine(email.Text);\r\n\r\n            LastRun current = new LastRun\r\n                                  {\r\n                                      UIDValidity = status.UIDValidity, \r\n                                      LargestUID = uid\r\n                                  };\r\n            SaveThisRun(current);\r\n        }\r\n        imap.Close();\r\n    }\r\n}\r\n<\/pre>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n' VB.NET\r\n\r\nImports Limilabs.Mail\r\nImports Limilabs.Client.IMAP\r\n\r\nFriend Class LastRun\r\n\tPublic Property UIDValidity () As Long\r\n\t\tGet\r\n\t\t\tReturn m_UIDValidity \r\n\t\tEnd Get\r\n\t\tSet\r\n\t\t\tm_UIDValidity = Value\r\n\t\tEnd Set\r\n\tEnd Property\r\n\tPrivate m_UIDValidity As Long\r\n\tPublic Property LargestUID() As Long\r\n\t\tGet\r\n\t\t\tReturn m_LargestUID\r\n\t\tEnd Get\r\n\t\tSet\r\n\t\t\tm_LargestUID = Value\r\n\t\tEnd Set\r\n\tEnd Property\r\n\tPrivate m_LargestUID As Long\r\nEnd Class\r\n\r\n\r\nPrivate Shared Sub Main(args As String())\r\n    Dim last As LastRun = LoadPreviousRun()\r\n\r\n    Using imap As New Imap()\r\n        imap.Connect(&quot;imap.example.com&quot;)\t\t' or ConnectSSL for SSL\r\n        imap.UseBestLogin(&quot;user&quot;, &quot;password&quot;)\r\n\r\n        Dim status As FolderStatus = imap.SelectInbox()\r\n\r\n        If last Is Nothing OrElse last.UIDValidity &lt;&gt; status.UIDValidity Then\r\n\t        uids = imap.GetAll()\r\n        Else\r\n\t        uids = imap.Search().Where(Expression.UID(Range.From(last.LargestUID)))\r\n        \tuids.Remove(last.LargestUID)\r\n        End If\r\n\r\n        For Each uid As Long In uids\r\n            Dim eml = imap.GetMessageByUID(uid)\r\n            Dim email As IMail = New MailBuilder().CreateFromEml(eml)\r\n\r\n            Console.WriteLine(email.Subject)\r\n            Console.WriteLine(email.Text)\r\n\r\n            Dim current As New LastRun() With { _\r\n                .UIDValidity = status.UIDValidity, _\r\n                .LargestUID = uid _\r\n            }\r\n            SaveThisRun(current)\r\n        Next\r\n        imap.Close()\r\n    End Using\r\nEnd Sub\r\n<\/pre>\n<h2>SaveThisRun, LoadPreviousRun methods<\/h2>\n<p>You need to write those methods on your own. They should save\/load last run data from\/to your preferred storage (such as database, file, registry).<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ C#\r\n\r\nprivate void SaveThisRun(LastRun run)\r\n{\r\n    \/\/ Your code that saves run data.\r\n}\r\n\r\nprivate LastRun LoadPreviousRun()\r\n{\r\n    \/\/ Your code that loads last run data (null on the first run).\r\n}\r\n<\/pre>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n' VB.NET\r\n\r\nPrivate Sub SaveThisRun(uid As LastRun )\r\n    ' Your code that saves run data.\r\nEnd Sub\r\n\r\nPrivate Function LoadPreviousRun() As LastRun\r\n    ' Your code that loads last run data (null on the first run).\r\nEnd Function\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This article describes how to receive new email messages using Mail.dll .NET IMAP library. In many situations you can relay on IMAP server to keep track which messages are unseen and just download unseen messages from IMAP server. However when user interaction or other program connecting and downloading emails may remove UNSEEN flag from the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[15,28,77,57],"class_list":["post-3265","post","type-post","status-publish","format-standard","hentry","category-mail-dll","tag-c","tag-imap","tag-imap-component","tag-vb-net"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/3265"}],"collection":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/comments?post=3265"}],"version-history":[{"count":26,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/3265\/revisions"}],"predecessor-version":[{"id":5505,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/3265\/revisions\/5505"}],"wp:attachment":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/media?parent=3265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/categories?post=3265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/tags?post=3265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}