Receiving new messages from POP3 server (Part
2)
Advanced topics
Summary: Presents advanced
code sample of receiving new messages. Highlights performance improvements, responsive
user interface, error-checking, old POP3 servers support and simple implementation
of message identifiers database.
Tutorial map:
Part 1 - Getting new messages
Part 2 - Advanced topics
Typical scenario: The mail client checks whether new messages have arrived
since last connection and wants to download new messages (if any). The mail
client allows user to abort operation, handles errors, keeps user interface
responsive during email operation.
Limitations: None.
Performance improvements
In Part 1 code sample,
Unique-IDs for all the messages in the mailbox are looked up in the database.
In real-world situations, mailboxes usually contain only a small number of new
messages beside total number of the messages. Another important fact is that
new messages are always appended to the end of the mailbox. It's impossible
that new message is followed by not new message. In other words:
Code example:
' MailBee License key Const LICENSE_KEY = "put your license key here" ' POP3 server name Const SERVER_NAME = "mail.server.com" ' POP3 server port (usually 110) Const SERVER_PORT = 110 ' POP3 account name Const ACCOUNT_NAME = "jdoe" ' POP3 account password Const ACCOUNT_PASSWORD = "secret" ' Path to a file that will be used as database Const DATABASE_FILENAME = "C:\database.txt" ' Succesful (No error) Const ERR_OK = 0 ' Error: The server does not support Unique-IDs Const ERR_POP3_COMMAND_NOT_SUPPORTED = 216 ' POP3 object declared global because it is used in ' more than one routine. Dim objPOP3 ' If True, email operation was aborted by user Dim blnAborted ' Displays a message describing the error occurred Sub ReportError(objPOP3) MsgBox "Error #" & objPOP3.ErrCode & "," & objPOP3.ErrDesc & _ ", Server responded: " & objPOP3.ServerResponse End Sub ' Returns message number of first of new messages in the mailbox. ' The search is performed using Unique-IDs of the messages ' ' Parameters: ' objPOP3 - POP3 object in the connected state. ' ' strStoredUIDs - CRLF-separated list of Unique-IDs of all messages ' in the mailbox as of moment of the previous connection. ' ' strCurrentUIDs - (output parameter) filled by this ' function with CRLF-separated list of Unique-IDs of all messages ' in the mailbox as of moment of the current connection. ' Function GetFirstOfNewMessages_UID(objPOP3, strStoredUIDs, ByRef strCurrentUIDs) Dim I, J ' Array of Unique-IDs of all messages in the ' mailbox as of moment of the previous connection. Dim arrStoredUIDs ' Array of Unique-IDs of all messages in the ' mailbox as of moment of the current connection. Dim arrCurrentUIDs ' Convert CRLF-separated list into array arrStoredUIDs = Split(strStoredUIDs, vbCrLf) strCurrentUIDs = "" ' Get Unique-IDs of all messages from POP3 server arrCurrentUIDs = objPOP3.Search If objPOP3.ErrCode = ERR_OK Then ' Successfully got Unique-IDs array from POP3 server ' Convert array into CRLF-separated list strCurrentUIDs = Join(arrCurrentUIDs, vbCrLf) ' Iterate through old messages from last to first For I = UBound(arrStoredUIDs) To LBound(arrStoredUIDs) Step -1 ' Lookup old message in current messages For J = UBound(arrCurrentUIDs) To LBound(arrCurrentUIDs) Step -1 If arrStoredUIDs(I) = arrCurrentUIDs(J) Then ' Old message was found in the list of current messages. ' All messages after found message are new. GetFirstOfNewMessages_UID = J + 1 Exit Function End If Next Next ' All messages have been scanned, but no matches with old ' messages have been found. All messages in the mailbox are new. GetFirstOfNewMessages_UID = 1 ElseIf objPOP3.ErrCode = ERR_POP3_COMMAND_NOT_SUPPORTED Then ' Non-fatal error, must rollback to Message-ID GetFirstOfNewMessages_UID = 0 Else ' Fatal error GetFirstOfNewMessages_UID = -1 End If End Function ' Returns message number of first of new messages in the mailbox. ' The search is performed using Message-IDs of the messages ' ' Parameters: ' objPOP3 - POP3 object in the connected state. ' ' strStoredMIDs - CRLF-separated list of Message-IDs of all messages ' in the mailbox as of moment of the previous connection. ' ' strCurrentMIDs - (output parameter) filled by this ' function with CRLF-separated list of Message-IDs of all messages ' in the mailbox as of moment of the current connection. ' Function GetFirstOfNewMessages_MID(objPOP3, strStoredMIDs, ByRef strCurrentMIDs) Dim I, J ' True if new message was found Dim blnNew ' Message object that holds message headers Dim objMsg ' Array of Message-IDs of all messages in the ' mailbox as of moment of the previous connection. Dim arrStoredMIDs ' Convert CRLF-separated list into array arrStoredMIDs = Split(strStoredMIDs, vbCrLf) strCurrentMIDs = "" ' No new messages found to the moment blnNew = False ' No new messages yet, so mark that first new ' message is outside the valid range. GetFirstOfNewMessages_MID = objPOP3.MessageCount + 1 ' Iterate through all messages in the mailbox For I = 1 To objPOP3.MessageCount ' Get message headers from POP3 server Set objMsg = objPOP3.RetrieveSingleMessageHeaders(I) If objPOP3.ErrCode <> 0 Then ' Return error GetFirstOfNewMessages_MID = -1 Exit Function End If If Not blnNew Then ' New messages not found yet ' Initially assume the message is new blnNew = True ' Try to find just retrived Message-ID ' in the array of old messages. For J = LBound(arrStoredMIDs) To UBound(arrStoredMIDs) If arrStoredMIDs(J) = objMsg.MessageID Then ' Message-ID was found, the message is not new blnNew = False Exit For End If Next If blnNew Then ' Message-ID was not found, the message is new. ' All subsequent messages will be new too. GetFirstOfNewMessages_MID = I End If End If ' Add Message-ID to the list of Message-IDs of current messages If Len(strCurrentMIDs) > 0 Then strCurrentMIDs = strCurrentMIDs & vbCrLf & objMsg.MessageID Else strCurrentMIDs = objMsg.MessageID End If Next End Function ' Checks for new messages and displays Subject field ' of each new message in the ListBox. Sub Command1_Click() Dim objMsg, I Dim fso, f ' strStoredIDs - CRLF-separated list of IDs (Unique-IDs or ' Message-IDs, if Unique-IDs are not supported) of all ' messages in the mailbox as of moment of the previous connection. Dim strStoredIDs ' strStoredIDs - CRLF-separated list of IDs (Unique-IDs or ' Message-IDs, if Unique-IDs are not supported) of all ' messages in the mailbox as of moment of the current connection. Dim strCurrentIDs ' Message number of first of new messages. This message is newer ' than any old message, and older than any other new message. Dim lFirstNew Set objPOP3 = CreateObject("MailBee.POP3") objPOP3.LicenseKey = LICENSE_KEY ' Make user interface responsive objPOP3.EnableEvents = True ' Connect to POP3 server If objPOP3.Connect(SERVER_NAME, SERVER_PORT, ACCOUNT_NAME, ACCOUNT_PASSWORD) Then ' Open text file that holds the database Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.OpenTextFile(DATABASE_FILENAME, 1, True) If Not f.AtEndOfStream Then ' Read array of IDs from the file strStoredIDs = f.ReadAll Else ' The file was empty strStoredIDs = "" End If f.Close ' Determine first of new messages using Unique-IDs lFirstNew = GetFirstOfNewMessages_UID(objPOP3, strStoredIDs, strCurrentIDs) If lFirstNew = 0 Then ' Unique-IDs are not supported by the POP3 server ' Determine first of new messages using Message-IDs lFirstNew = GetFirstOfNewMessages_MID(objPOP3, strStoredIDs, strCurrentIDs) End If ' Exit the routine if user wants to close the app If blnAborted Then Exit Sub If lFirstNew < 0 Then ' Report error to user ReportError objPOP3 Else ' Loop from the first of new messages to the end of the ' mailbox. If lFirstNew > objPOP3.MessageCount, the loop ' is executed zero times (no new messages were found). For I = lFirstNew To objPOP3.MessageCount ' Download entire message Set objMsg = objPOP3.RetrieveSingleMessage(I) ' Exit the routine if user wants to close the app If blnAborted Then Exit Sub ' Display Subject of the message List1.AddItem objMsg.Subject Next ' Open the text file for writing Set f = fso.OpenTextFile(DATABASE_FILENAME, 2, True) ' Store IDs in the file f.Write strCurrentIDs f.Close End If ' Disconnect on finish objPOP3.Disconnect ElseIf Not blnAborted Then ' Report connection error to user ReportError objPOP3 End If End Sub ' Initialize Sub Form_Load() blnAborted = False Set objPOP3 = Nothing End Sub ' Abort operation when user wants to exit the app Sub Form_Unload(Cancel As Integer) If Not objPOP3 Is Nothing Then blnAborted = True objPOP3.Abort End If End Sub
See Also:
RetrieveSingleMessage
Method
RetrieveSingleMessageHeaders
Method
Search Method
Copyright © 2002-2024, AfterLogic Corporation. All rights reserved.