Sometimes the developers want to leave a copy of email on the POP3/IMAP4/Exchange server for backup, so they don't delete the email after the email was received. The common issue is how to detect if the email has been retrieved by the application already, otherwise, all the emails on the server will be retrieved again and again. In this case, we should use the Unique Identifier (UIDL) to avoid to receive the same email more than once.
Using Unique Identifier (UIDL)
The mail server assigns an unique identifier for every email in the same account. You can get the UIDL for every email by MailInfo.UIDL property. To avoid to receive the same email twice, the best way is storing the UIDL of email retrieved to a text file or database. Next time before you retrieve the email, compare your local uidl list with remote uidl. If this uidl exists in your local uidl list, then you don't receive it, otherwise you should receive it.
Difference with UIDL in POP3/IMAP4/Exchange Web Service/WebDAV
UIDL is always unique in IMAP4 and it is always increasing integer. UIDL in POP3 can be any valid asc-ii characters, and the UIDL may be reused by POP3 server if the email with the UIDL has been deleted from the server, so we suggest that you should remove the uidl from your local uidl list if the uidl is no longer existed on the POP3 server. UIDL is also unique in Exchange Web Service/WebDAV, but the UIDL is string but not integer. Every email has a unique identifier (UIDL) on IMAP4 server. It is a 32bit integer and it is always unique in your email account life time. So we can use the integer as file name to identify if the email has been downloaded. There is a little bit different in POP3 server. The UIDL is only unique in the email life time. That means if the email was deleted from the server, other email can use the old unique identifier. Another problem is: UIDL in POP3 server can be any number or characters, so we cannot use UIDL as the file name, because UIDL may contain invalid characters for file name. For Exchange Web Service/WebDAV, although the UIDL is always unique in your email account, but UIDL may also contain invalid characters for file name.
Total Solution
UIDLManager provides an easy way to maintain UIDL between your server and your local client. How does it work? It stores UIDL collection to a local disk file and you can use this object to add, remove and search UIDL with this local file.
UIDL File Format
With UIDLManager, you can use any file name as the UIDL local file, but we suggest that you use different UIDL file for different email account. In the UIDL file, each line presents a UIDL information.
"mailserver#user#protocol","UIDL","Local File Name","Download Date Time","Flags" "mailserver#user#protocol","UIDL1","Local File Name1","Download Date Time","Flags"
You can use UIDLManager to record the UIDL of the email that you have downloaded; you can also associate the local file name and flags to UIDLItem object. Then you can use UIDLManager to detect if the email has been downloaded, when it has been downloaded. If it has been downloaded, what local file it has saved to.
Example
[Visual Basic, C#, C++] The following example demonstrates how To retrieve email with EAGetMail POP3 & IMAP Component, but it doesn't demonstrates the events and mail parsing usage. To get the full samples of EAGetMail, please refer to Samples section.
[Visual Basic] Imports System Imports System.Globalization Imports System.IO Imports System.Text Imports EAGetMail Public Class TestClass ' Generate an unqiue email file name based on date time. Shared Function _generateFileName(ByVal sequence As Integer) As String Dim currentDateTime As DateTime = DateTime.Now Return String.Format("{0}-{1:000}-{2:000}.eml", currentDateTime.ToString("yyyyMMddHHmmss", New CultureInfo("en-US")), currentDateTime.Millisecond, sequence) End Function Public Sub ReceiveMail(server As String, user As String, password As String, useSsl As Boolean) Dim isUidlLoaded As Boolean = False Dim isLeaveCopy As Boolean = True ' leave a copy of message on server ' UIDL is the identifier of every email on POP3/IMAP4/Exchange server, to avoid retrieve ' the same email from server more than once, we record the email UIDL retrieved every time ' if you delete the email from server every time and not to leave a copy of email on ' the server, then please remove all the function about uidl. ' UIDLManager wraps the function to write/read uidl record from a text file. Dim oUIDLManager As UIDLManager = New UIDLManager() Try ' Create a folder named "inbox" under current directory ' to save the email retrieved. Dim localInbox As String = String.Format("{0}\inbox", Directory.GetCurrentDirectory()) Dim uidlFile As String = String.Format("{0}\uidl.txt", localInbox) ' If the folder is not existed, create it. If Not Directory.Exists(localInbox) Then Directory.CreateDirectory(localInbox) End If ' To receive email from IMAP4 server, please change ' ServerProtocol.Pop3 to ServerProtocol.Imap4 in MailServer constructor ' To receive email with Exchange Web Service, please change ' ServerProtocol.Pop3 to ServerProtocol.ExchangeEWS to MailServer constructor ' To receive email with Exchange WebDAV, please change ' ServerProtocol.Pop3 to ServerProtocol.ExchangeWebDAV to MailServer constructor ' Exchange Server supports POP3/IMAP4 protocol as well, but in Exchange 2007 ' Or later version, POP3/IMAP4 service Is disabled by default. If you don't want to use POP3/IMAP4 ' to download email from Exchange Server, you can use Exchange Web Service (Exchange 2007-2019 Or ' later version) Or WebDAV (Exchange 2000/2003) protocol. ' Most modern email server require SSL/TLS connection, ' set useSsl to true Is recommended. Dim oServer As New MailServer(server, user, password, useSsl, ServerAuthType.AuthLogin, ServerProtocol.Pop3) ' POP3 port Is 110, POP3 SSL port Is 995 ' IMAP4 port Is 143, IMAP4 SSL port Is 993. ' EWS/WebDAV, please ignore Port property. If oServer.Protocol = ServerProtocol.Pop3 Then oServer.Port = If(useSsl, 995, 110) ElseIf oServer.Protocol = ServerProtocol.Imap4 Then oServer.Port = If(useSsl, 993, 143) End If ' Load existed uidl records to UIDLManager oUIDLManager.Load(uidlFile) isUidlLoaded = True Console.WriteLine("Connecting server ...") Dim oClient As New MailClient("TryIt") oClient.Connect(oServer) Console.WriteLine("Retrieving email list ...") Dim infos() As MailInfo = oClient.GetMailInfos() Console.WriteLine("Total {0} email(s)", infos.Length) ' Remove the local uidl that is not existed on the server, oUIDLManager.SyncUIDL(oServer, infos) oUIDLManager.Update() For i As Integer = 0 To infos.Length - 1 Console.WriteLine("Checking {0}/{1} ...", i + 1, infos.Length) Dim info As MailInfo = infos(i) If oUIDLManager.FindUIDL(oServer, info.UIDL) IsNot Nothing Then Console.WriteLine("This email has been downloaded before, skip ...") Continue For End If ' Generate an unqiue email file name based on date time. Dim fileName As String = _generateFileName(i + 1) Dim fullPath As String = String.Format("{0}\{1}", localInbox, fileName) Console.WriteLine("Downloading {0}/{1} ...", i + 1, infos.Length) Dim oMail As Mail = oClient.GetMail(info) ' Save email to local disk oMail.SaveAs(fullPath, True) If isLeaveCopy Then ' Add uidl to uidl file to avoid we retrieve it next time. oUIDLManager.AddUIDL(oServer, info.UIDL, fileName) Else ' Mark email as deleted on server. Console.WriteLine("Deleting ... {0}/{1}", i + 1, infos.Length) oClient.Delete(info) ' Remove UIDL from local uidl file. oUIDLManager.RemoveUIDL(oServer, info.UIDL) End If Next Console.WriteLine("Disconnecting ...") ' Delete method just mark the email as deleted, ' Quit method expunge the emails from server permanently. oClient.Quit() Console.WriteLine("Completed!") Catch ep As Exception Console.WriteLine("Error: {0}", ep.Message) End Try ' Update the uidl list to local uidl file and then we can load it next time. If isUidlLoaded Then oUIDLManager.Update() End If End Sub End Class
[C#] using System; using System.IO; using System.Globalization; using System.Text; using EAGetMail; class TestClass { // Generate an unqiue email file name based on date time static string _generateFileName(int sequence) { DateTime currentDateTime = DateTime.Now; return string.Format("{0}-{1:000}-{2:000}.eml", currentDateTime.ToString("yyyyMMddHHmmss", new CultureInfo("en-US")), currentDateTime.Millisecond, sequence); } public void ReceiveMail(string server, string user, string password, bool useSsl) { bool isUidlLoaded = false; bool isLeaveCopy = true; // leave a copy of message on server. // UIDL is the identifier of every email on POP3/IMAP4/Exchange server, to avoid retrieve // the same email from server more than once, we record the email UIDL retrieved every time // if you delete the email from server every time and not to leave a copy of email on // the server, then please remove all the function about uidl. // UIDLManager wraps the function to write/read uidl record from a text file. UIDLManager oUIDLManager = new UIDLManager(); try { // Create a folder named "inbox" under current directory // to save the email retrieved. string localInbox = string.Format("{0}\\inbox", Directory.GetCurrentDirectory()); string uidlFile = string.Format("{0}\\uidl.txt", localInbox); // If the folder is not existed, create it. if (!Directory.Exists(localInbox)) { Directory.CreateDirectory(localInbox); } // To receive email from IMAP4 server, please change // ServerProtocol.Pop3 to ServerProtocol.Imap4 in MailServer constructor // To receive email with Exchange Web Service, please change // ServerProtocol.Pop3 to ServerProtocol.ExchangeEWS to MailServer constructor // To receive email with Exchange WebDAV, please change // ServerProtocol.Pop3 to ServerProtocol.ExchangeWebDAV to MailServer constructor // Exchange Server supports POP3/IMAP4 protocol as well, but in Exchange 2007 // or later version, POP3/IMAP4 service is disabled by default. If you don't want to use POP3/IMAP4 // to download email from Exchange Server, you can use Exchange Web Service (Exchange 2007-2019 or // later version) or WebDAV (Exchange 2000/2003) protocol. // Most modern email server require SSL/TLS connection, // set useSsl to true is recommended. MailServer oServer = new MailServer(server, user, password, useSsl, ServerAuthType.AuthLogin, ServerProtocol.Pop3); // POP3 port is 110, POP3 SSL port is 995 // IMAP4 port is 143, IMAP4 SSL port is 993. // EWS/WebDAV, please ignore Port property. if (oServer.Protocol == ServerProtocol.Pop3) { oServer.Port = (useSsl) ? 995 : 110; } else if (oServer.Protocol == ServerProtocol.Imap4) { oServer.Port = (useSsl) ? 993 : 143; } // Load existed uidl records to UIDLManager oUIDLManager.Load(uidlFile); isUidlLoaded = true; Console.WriteLine("Connecting server ..."); MailClient oClient = new MailClient("TryIt"); oClient.Connect(oServer); Console.WriteLine("Retreiving email list ..."); MailInfo[] infos = oClient.GetMailInfos(); Console.WriteLine("Total {0} email(s)", infos.Length); // Remove the local uidl that is not existed on the server, oUIDLManager.SyncUIDL(oServer, infos); oUIDLManager.Update(); for (int i = 0; i < infos.Length; i++) { Console.WriteLine("Checking {0}/{1} ...", i + 1, infos.Length); MailInfo info = infos[i]; if (oUIDLManager.FindUIDL(oServer, info.UIDL) != null) { Console.WriteLine("This email has been downloaded, skip ..."); continue; } // Generate an unqiue email file name based on date time. string fileName = _generateFileName(i + 1); string fullPath = string.Format("{0}\\{1}", localInbox, fileName); Console.WriteLine("Downloading {0}/{1} ...", i + 1, infos.Length); Mail oMail = oClient.GetMail(info); // Save mail to local file oMail.SaveAs(fullPath, true); if (isLeaveCopy) { // Add uidl to uidl file to avoid we retrieve it next time. oUIDLManager.AddUIDL(oServer, info.UIDL, fileName); } else { // Mark the email as deleted on server. Console.WriteLine("Deleting ... {0}/{1}", i + 1, infos.Length); oClient.Delete(info); // Remove UIDL from local uidl file. oUIDLManager.RemoveUIDL(oServer, info.UIDL); } } Console.WriteLine("Disconnecting ..."); // Delete method just mark the email as deleted, // Quit method expunge the emails from server permanently. oClient.Quit(); Console.WriteLine("Completed!"); } catch (Exception ep) { Console.WriteLine("Error: {0}", ep.Message); } // Update the uidl list to local uidl file and then we can load it next time. if (isUidlLoaded) { oUIDLManager.Update(); } } }
[C++/CLI] using namespace System; using namespace System::Globalization; using namespace System::IO; using namespace EAGetMail; //add EAGetMail namespace // Generate an unqiue email file name based on date time static String ^ _generateFileName(int sequence) { DateTime currentDateTime = DateTime::Now; return String::Format("{0}-{1:000}-{2:000}.eml", currentDateTime.ToString("yyyyMMddHHmmss", gcnew CultureInfo("en-US")), currentDateTime.Millisecond, sequence); } void ReceiveMail(String ^server, String ^user, String ^password, bool useSsl) { bool isUidlLoaded = false; bool isLeaveCopy = true; // leave a copy of message on server. // UIDL is the identifier of every email on POP3/IMAP4/Exchange server, to avoid retrieve // the same email from server more than once, we record the email UIDL retrieved every time // if you delete the email from server every time and not to leave a copy of email on // the server, then please remove all the function about uidl. // UIDLManager wraps the function to write/read uidl record from a text file. UIDLManager ^oUIDLManager = gcnew UIDLManager(); try { // Create a folder named "inbox" under current directory // to save the email retrieved. String ^localInbox = String::Format("{0}\\inbox", Directory::GetCurrentDirectory()); String ^uidlFile = String::Format("{0}\\uidl.txt", localInbox); // If the folder is not existed, create it. if (!Directory::Exists(localInbox)) { Directory::CreateDirectory(localInbox); } // To receive email from IMAP4 server, please change // ServerProtocol.Pop3 to ServerProtocol.Imap4 in MailServer constructor // To receive email with Exchange Web Service, please change // ServerProtocol.Pop3 to ServerProtocol.ExchangeEWS to MailServer constructor // To receive email with Exchange WebDAV, please change // ServerProtocol.Pop3 to ServerProtocol.ExchangeWebDAV to MailServer constructor // Exchange Server supports POP3/IMAP4 protocol as well, but in Exchange 2007 // or later version, POP3/IMAP4 service is disabled by default. If you don't want to use POP3/IMAP4 // to download email from Exchange Server, you can use Exchange Web Service (Exchange 2007-2019 or // later version) or WebDAV (Exchange 2000/2003) protocol. // Most modern email server require SSL/TLS connection, // set useSsl to true is recommended. MailServer ^oServer = gcnew MailServer(server, user, password, useSsl, ServerAuthType::AuthLogin, ServerProtocol::Pop3); // POP3 port is 110, POP3 SSL port is 995 // IMAP4 port is 143, IMAP4 SSL port is 993. // EWS/WebDAV, please ignore Port property. if (oServer->Protocol == ServerProtocol::Pop3) { oServer->Port = (useSsl) ? 995 : 110; } else if (oServer->Protocol == ServerProtocol::Imap4) { oServer->Port = (useSsl) ? 993 : 143; } // Load existed uidl records to UIDLManager oUIDLManager->Load(uidlFile); isUidlLoaded = true; Console::WriteLine("Connecting server ..."); MailClient ^oClient = gcnew MailClient("TryIt"); oClient->Connect(oServer); Console::WriteLine("Retreiving email list ..."); array<MailInfo^>^infos = oClient->GetMailInfos(); Console::WriteLine("Total {0} email(s)", infos->Length); // Remove the local uidl which is not existed on the server. oUIDLManager->SyncUIDL(oServer, infos); oUIDLManager->Update(); for (int i = 0; i < infos->Length; i++) { Console::WriteLine("Checking {0}/{1}", i + 1, infos->Length); MailInfo ^info = infos[i]; if (oUIDLManager->FindUIDL(oServer, info->UIDL) != nullptr) { Console::WriteLine("This email has been downloaded before, skip ..."); continue; } // Generate an unqiue email file name based on date time String^ fileName = _generateFileName(i + 1); String^ fullPath = String::Format("{0}\\{1}", localInbox, fileName); Console::WriteLine("Downloading {0}/{1}", i + 1, infos->Length); Mail ^oMail = oClient->GetMail(info); // Save email to local disk oMail->SaveAs(fullPath, true); if (isLeaveCopy) { // Add uidl to uidl file to avoid we retrieve it next time. oUIDLManager->AddUIDL(oServer, info->UIDL, fileName); } else { // Mark email as deleted on server. Console::WriteLine("Deleting ... {0}/{1}", i + 1, infos->Length); oClient->Delete(info); // Remove UIDL from local uidl file. oUIDLManager->RemoveUIDL(oServer, info->UIDL); } } Console::WriteLine("Disconnecting ..."); // Delete method just mark the email as deleted, // Quit method expunge the emails from server permanently. oClient->Quit(); Console::WriteLine("Completed!"); } catch (Exception ^ep) { Console::WriteLine("Error: {0}", ep->Message); } // Update the uidl list to local uidl file and then we can load it next time. if (isUidlLoaded) { oUIDLManager->Update(); } }
See Also
Using EAGetMail POP3 and IMAP4 Component
User Authentication and SSL Connection
Enable TLS 1.2 on Windows XP/2003/2008/7/2008 R2
Using Gmail IMAP4 OAUTH
Using Gmail/GSuite Service Account + IMAP4 OAUTH
Using Office365 EWS OAUTH
Using Office365 EWS OAUTH in Background Service
Using Hotmail IMAP4 OAUTH
Digital Signature and E-mail Encryption/Decryption
Parse Bounced Email (delivery-report)
Work with winmail.dat (TNEF Parser)
EAGetMail Namespace References
EAGetMail POP3 and IMAP4 Component Samples
Online Tutorials
Using UIDL Function to Mark the Email has been downloaded/read in C# - Tutorial
Using UIDL Function to Mark the Email has been downloaded/read in VB.NET - Tutorial
Using UIDL Function to Mark the Email has been downloaded/read in C++/CLI - Tutorial