- Products
- Purchase
Order Online Maintenance Renewal Resellers - Support
Helpdesk Online Documentation Web Forum - Our Clients
- About
About us Services Contact
From AfterLogic Wiki
In SMTP part of this sample we made the bounce e-mails arrive to the specified single e-mail account.
Each bounced e-mail contains (along with other info) the failed e-mail address. This failed address is what we want to know. The task looks pretty simple – all you have to do is to scan the bounced body for typical words that would determine the bad address. But there is a hidden danger: each mail server uses its own bounce message format. While they have almost the same "From" and "Subject" fields, the bad address can be at any place of the message. The typical bounced message form MailEnable server looks like this:
From: POSTMASTER@domain.com To: jdoe@domain.com Subject: Message Delivery Failure MailEnable: Message Delivery Failure.
The following recipient(s) could not be reached: Recipient: [SMTP: bill@domain.com] Reason: The message could not be delivered because the domain name (domain.com) does not appear to be registered.
The function GetInvalidEmailAddressME() checks whether the message is bounced and extracts the failed address from the bounced message. Due to different format of the bounced message this function is valid only for MailEnable servers. For example, if you are using the Communigate Pro server, then the bounce message looks like this:
From: MAILER-DAEMON@domain.local To: jdoe@localhost Subject: Undeliverable mail: Failed to deliver to '<bill@localhost>'
As you can see, this bounced message is almost the same as the previous one. It does not matter which server you use, the bounce message always has From, To and Subject fields, the bounce message will also have the failed address in its body. The function GetInvalidEmailAddressCP() is almost identical to the previous one; the difference is only in checking the message fields and searching for the failed address. It is vital to support as many bounced e-mail formats as possible. That is why you need to modify the GetInvalidEmailAddress() function to suit the bounced e-mail format used by the servers to which you are sending mail.
Note: In some cases you may want to scan the bounced e-mails for other information. E.g. do not remove e-mail address if the bounced message arrived due to a temporary problem: the mailbox is over quota, the mail server is down, etc. Bounce messages can be divided into two types: hard ones and soft ones. Hard bounces occur if there is a nonexistent account or domain. Other failures, such as a full mailbox or temporarily unavailable domain, are soft bounces. You can count hard and soft bounces for each address in your database. Probably, the next attempt to send a message to the address which has some soft bounces will succeeded. Of course, if one address has 10 or more soft bounces, it can be marked as hard one. Nevertheless, one hard bounce does not always mean that the address is really invalid; it would be more reliable to delete the address from the database after at least two hard bounces. To determine the soft bounces your application should scan the text of the bounced messages looking for phrases that indicate the reason for the bounce, such as "delivery failure", "mailbox full", etc...
Code example:
In this sample we retrieve the bounced e-mails from the specified account and then extract the failed e-mail address from each bounced e-mail. The failed address is passed to the RemoveEmailFromDatabase subroutine which must remove the failed address from the database (you should implement this code yourself to operate with your database). The application also deletes the bounced email from the server to avoid processing the next time.
// Create POP3 object Pop3 pop = new Pop3(); // Enable logging to file pop.Log.Enabled = true; pop.Log.Filename = @"C:\log.txt"; pop.Log.Clear(); // Connect to POP3 server pop.Connect("mail.domain.com"); pop.Login("bounce", "secret"); // Download headers and bodies of all messages. MailMessageCollection msgs = pop.DownloadMessageHeaders(1, -1, -1); // Loop through all messages in the mailbox foreach (MailMessage msg in msgs) { string strLine = msg.BodyPlainText; Console.WriteLine("From: " + msg.From.Email); // Get failed email address string str_invalid_email = GetInvalidEmailAddressME(msg); // If str_invalid_email is non-empty then failed email // address was found if (str_invalid_email.Length > 0) { // Remove failed email from database RemoveEmailFromDatabase(str_invalid_email); // Display invalid adress Console.WriteLine("Invalid email: " + str_invalid_email); // Delete bounced email from server to avoid // processing it next time pop.DeleteMessage(msg.IndexOnServer); } } // Disconnect from POP3 server pop.Disconnect(); // The function checks whether the message is bounced and extracts // failed address // from bounced message. Valid only for MailEnable servers static string GetInvalidEmailAddressME(MailMessage msg) { string str_invalid_email = msg.BodyPlainText; // Check if this is a bounced message report if (msg.Subject.IndexOf("Delivery Failure") == -1) { return ""; } if (msg.From.ToString().IndexOf("POSTMASTER") == -1) { return ""; } // Now we're sure this is a bounced message report int i_start; i_start = str_invalid_email.IndexOf("SMTP:"); // Check if bounced message report contains "Recipient:" field if (i_start == -1) { return ""; } // Get failed address i_start += 5; i_end = str_invalid_email.IndexOf("]",i_start); str_invalid_email.Substring(i_start, i_end); return str_invalid_email; } // The function checks whether the message is bounced and extracts // failed address // from bounced message. Valid only for Communigate Pro servers static string GetInvalidEmailAddressCP(MailMessage msg) { string str_invalid_email = msg.BodyPlainText; // Check if this is a bounced message report if (msg.Subject.IndexOf("Undeliverable mail") == -1) { return ""; } if (msg.From.ToString().IndexOf("MAILER-DAEMON") == -1) { return ""; } // Now we're sure this is a bounced message report int i_start; i_start = str_invalid_email.IndexOf("to '<"); // Check if bounced message report contains // "Failed to deliver to " field if (i_start == -1) { return ""; } // Get failed address i_start += 5; i_end = str_invalid_email.IndexOf("]",i_start); str_invalid_email.Substring(i_start, i_end); return str_invalid_email; } // This function must remove (or disable) specified // email address from mailing list static void RemoveEmailFromDatabase(string str_invalid_email) { // TODO: Add your code here }
Dim pop As New Pop3 ' Enable logging to file pop.Log.Enabled = True pop.Log.Filename = "C:\log.txt" pop.Log.Clear() ' Connect to POP3 server pop.Connect("mail.domain.com") pop.Login("jdoe", "secret") ' Download headers and bodies for all messages. Dim msgs As MailMessageCollection = pop.DownloadMessageHeaders(1, -1, -1) ' Loop through all messages in the mailbox Dim msg As MailMessage For Each msg In msgs Dim strLine As String = msg.BodyPlainText Console.WriteLine("From: " + msg.From.Email) ' Get failed email address Dim str_invalid_email As String = GetInvalidEmailAddressME(msg) ' If str_invalid_email is non-empty then failed email ' address was found If str_invalid_email.Length > 0 Then 'Remove failed email from database RemoveEmailFromDatabase(str_invalid_email) ' Display invalid address Console.WriteLine("Invalid email: " & str_invalid_email) ' Delete bounced email from server to avoid ' processing it next time pop.DeleteMessage(msg.IndexOnServer) End If Next Console.ReadLine() ' Disconnect from POP3 server pop.Disconnect() ' The function checks whether the message is bounced and extracts ' failed address ' from bounced message. Valid only for MailEnable servers Function GetInvalidEmailAddressME(ByVal msg As MailMessage) As String Dim str_invalid_email As String = msg.BodyPlainText ' Check if this is a bounced message report If msg.Subject.IndexOf("Delivery Failure") = -1 Then Return "" End If If msg.From.ToString().IndexOf("POSTMASTER") = -1 Then Return "" End If ' Now we're sure this is a bounced message report Dim i_start As Integer, i_end As Integer i_start = str_invalid_email.IndexOf("SMTP:") ' Check if bounced message report contains "Recipient:" field If i_start = -1 Then Return "" End If ' Get failed address i_start += 5 i_end = str_invalid_email.IndexOf("]", i_start) str_invalid_email.Substring(i_start, i_end) Return str_invalid_email End Function ' The function checks whether the message is bounced and extracts ' failed address ' from bounced message. Valid only for Communigate Pro servers Function GetInvalidEmailAddressCP(ByVal msg As MailMessage) As String Dim str_invalid_email As String = msg.BodyPlainText ' Check if this is a bounced message report If msg.Subject.IndexOf("Undeliverable mail") = -1 Then Return "" End If If msg.From.ToString().IndexOf("MAILER-DAEMON") = -1 Then Return "" End If ' Now we're sure this is a bounced message report Dim i_start As Integer, i_end As Integer i_start = str_invalid_email.IndexOf("to '<") ' Check if bounced message report contains ' "Failed to deliver to " field If i_start = -1 Then Return "" End If ' Get failed address i_start += 5 i_end = str_invalid_email.IndexOf("]", i_start) str_invalid_email.Substring(i_start, i_end) Return str_invalid_email End Function ' This function must remove (or disable) specified ' email address from mailing list Sub RemoveEmailFromDatabase(ByVal str_invalid_email As String) ' TODO: Add your code here End Sub