Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

deleting emails via POP3

Posted on 2011-10-20
10
Medium Priority
?
301 Views
Last Modified: 2012-05-12
I'm writing a program that connects to our Exchange server via POP3, then read all the emails in the mailbox, saves them to text files, and then deletes the emails from the inbox.

Everything works fine except the deleting of the emails. When the program sends the QUIT command to the mailserver it gets a "+OK" response which denotes that the email was marked for deletion. I then close the connection to the mailserver. As far as I understand, when I close the connection all the emails that are marked for deletion should be deleted.

What am I missing?

I'll post my code in two sections so you won't have to filter through a bunch of lines.
Here is my deleteMessages and disconnect subroutine:
     Private Sub deleteMessages(ByRef allIsGood As Boolean, ByVal numberOfMessages As Integer, ByRef errorMessages As String)
        Dim tempStr As String
        Dim data As String
        Dim szData() As Byte
        Dim msgText As String = ""

        Try
            Dim i As Integer = Nothing
            For i = 1 To numberOfMessages Step i + 1
                data = "DELE " & 5.ToString & vbCrLf
                szData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
                netStrm.Write(szData, 0, szData.Length)
                tempStr = rdStrm.ReadLine()
                If tempStr.StartsWith("-ERR") Then
                    errorMessages = errorMessages + " Could not delete message with index " + i.ToString + vbCrLf + tempStr + vbCrLf
                    allIsGood = False
                End If
            Next
        Catch ex As InvalidOperationException
            errorMessages = errorMessages + " Could not delete messages: " & vbCrLf & Err.ToString + vbCrLf
            allIsGood = False
            Exit Sub
        End Try
    End Sub

    Private Sub disconnect(ByRef allIsGood As Boolean, ByVal numberOfMessages As Integer, ByRef errorMessages As String)
        
        Dim data As String = "QUIT"
        Dim szData() As Byte = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
        netStrm.Write(szData, 0, szData.Length)
        Dim tempStr As String = rdStrm.ReadLine()
        If tempStr.StartsWith("-ERR") Then
            errorMessages = errorMessages + " Could not disconnect from server " + tempStr + vbCrLf
            allIsGood = False
        End If
        Try
            rdStrm.Close()
            netStrm.Close()
            server.Close()
        Catch ex As Exception
            errorMessages = errorMessages + " Could not disconnect from server " + ex.ToString + vbCrLf
            allIsGood = False
        End Try
        
    End Sub

Open in new window


Here is my entire code behind
Imports System
Imports System.Net.Sockets
Imports System.Text
Imports System.IO
Imports Microsoft.VisualBasic
Public Class Form2

    Public mailServer As String = System.Configuration.ConfigurationSettings.AppSettings("mailServer")
    Public userName As String = System.Configuration.ConfigurationSettings.AppSettings("userName")
    Public password As String = System.Configuration.ConfigurationSettings.AppSettings("password")
    Public portNum As String = System.Configuration.ConfigurationSettings.AppSettings("portNum")
    Public saveFilesLocation As String = System.Configuration.ConfigurationSettings.AppSettings("saveFilesLocation")
    Public orderNoDelimiter As String = System.Configuration.ConfigurationSettings.AppSettings("orderNoDelimiter")
    Public orderNoLength As Integer = System.Configuration.ConfigurationSettings.AppSettings("orderNoLength")
    Public bodyDelimiter As String = System.Configuration.ConfigurationSettings.AppSettings("bodyDelimiter")
    Public ErrorLogLocation As String = System.Configuration.ConfigurationSettings.AppSettings("ErrorLogLocation")

    Public server As TcpClient
    Public netStrm As NetworkStream
    Public rdStrm As StreamReader

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim errorMessages As String = Nothing
        Dim allIsGood As Boolean = True
        Dim numberOfMessages As Integer = Nothing
       
        connect(allIsGood, numberOfMessages, errorMessages)
        If allIsGood = True Then
            getMessage(allIsGood, numberOfMessages, errorMessages)
        End If
        If allIsGood = True Then
            deleteMessages(allIsGood, numberOfMessages, errorMessages)
        End If

        disconnect(allIsGood, numberOfMessages, errorMessages)

        If allIsGood = False Then
            writeLogFile(errorMessages)
        End If
        Me.Close()

    End Sub

    Private Sub connect(ByRef allIsgood As Boolean, ByRef numberOfMessages As Integer, ByRef errorMessages As String)
       
        Dim data As String
        Dim szData() As Byte
        Dim POPResponse As String

        Try
            server = New TcpClient(mailServer, portNum)
            netStrm = server.GetStream
            rdStrm = New StreamReader(server.GetStream)
        Catch exc As Exception
            errorMessages = errorMessages + "Could not connect to server" + vbCrLf + exc.Message.ToString + vbCrLf
            allIsgood = False
            Exit Sub
        End Try

        data = "USER " + userName + vbCrLf
        szData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
        netStrm.Write(szData, 0, szData.Length)
        POPResponse = rdStrm.ReadLine
        If POPResponse.StartsWith("-ERR") Then
            errorMessages = errorMessages + "Invalid username for login" + vbCrLf
            allIsgood = False
            Exit Sub
        End If

        data = "PASS " + password + vbCrLf
        szData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
        netStrm.Write(szData, 0, szData.Length)
        POPResponse = rdStrm.ReadLine
        If POPResponse.StartsWith("-ERR") Then
            errorMessages = errorMessages + "Invalid password for login" + vbCrLf
            allIsgood = False
            Exit Sub
        End If

        data = "STAT" + vbCrLf
        szData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
        netStrm.Write(szData, 0, szData.Length)
        POPResponse = rdStrm.ReadLine
        If POPResponse.StartsWith("-ERR") Then
            errorMessages = errorMessages + " " = POPResponse.ToString + vbCrLf
            allIsgood = False
            Exit Sub
        End If

        data = "Stat" + password + vbCrLf
        szData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
        netStrm.Write(szData, 0, szData.Length)
        POPResponse = rdStrm.ReadLine
        If POPResponse.StartsWith("-ERR") Then
            errorMessages = errorMessages + "Could not log you in" + vbCrLf
            allIsgood = False
            Exit Sub
        End If

        Dim splitPOPResponse() As String = POPResponse.Split(" ")
        numberOfMessages = CInt(splitPOPResponse(1))
        Return
    End Sub

    Private Sub getMessage(ByRef allIsGood As Boolean, ByVal numberOfMessages As Integer, ByRef errorMessages As String)
        Dim tempStr As String
        Dim data As String
        Dim szData() As Byte
        Dim msgText As String = ""

        Try
            Dim i As Integer = Nothing
            For i = 1 To numberOfMessages Step i + 1
                data = "RETR " & i.ToString & vbCrLf
                szData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
                netStrm.Write(szData, 0, szData.Length)
                tempStr = rdStrm.ReadLine()
                If tempStr.StartsWith("-ERR") Then
                    While (tempStr <> ".")
                        msgText = msgText & tempStr & vbCrLf
                        tempStr = rdStrm.ReadLine
                    End While
                End If
                writeMsgToFile(allIsGood, msgText, errorMessages)
            Next
        Catch ex As InvalidOperationException
            errorMessages = errorMessages + " Message Retrival Failed: " & vbCrLf & Err.ToString + vbCrLf
            allIsGood = False
        End Try
    End Sub

    Private Sub writeMsgToFile(ByRef allIsGood As Boolean, ByVal msgText As String, ByRef errorMessages As String)


        Dim ordrNumLocation As Integer = InStr(msgText, orderNoDelimiter)
        Dim orderNum As String = msgText.Substring(ordrNumLocation + orderNoDelimiter.Length - 1, orderNoLength)

        Dim bodyStartLocation As Integer = InStr(msgText, bodyDelimiter)
        Dim getBodyLength As Integer = msgText.Length - bodyStartLocation + bodyDelimiter.Length - 1
        Dim body As String = msgText.Substring(bodyStartLocation - bodyDelimiter.Length, getBodyLength)

        Dim splitBody() As String = body.Split("\t")
        Dim nacho As Integer = splitBody.Length

        Dim fileToWrite As New System.IO.StreamWriter(saveFilesLocation + orderNum + ".txt")

        Dim i As Integer = 0
        Try
            For i = 0 To splitBody.Length - 1 Step i + 1
                fileToWrite.WriteLine(splitBody(i) + vbCrLf)
            Next
            fileToWrite.Close()
        Catch ex As Exception
            errorMessages = errorMessages + " Could not write file " + orderNum.ToString + ".txt" + vbCrLf
            allIsGood = False
        End Try
    End Sub

    Private Sub deleteMessages(ByRef allIsGood As Boolean, ByVal numberOfMessages As Integer, ByRef errorMessages As String)
        Dim tempStr As String
        Dim data As String
        Dim szData() As Byte
        Dim msgText As String = ""

        Try
            Dim i As Integer = Nothing
            For i = 1 To numberOfMessages Step i + 1
                data = "DELE " & 5.ToString & vbCrLf
                szData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
                netStrm.Write(szData, 0, szData.Length)
                tempStr = rdStrm.ReadLine()
                If tempStr.StartsWith("-ERR") Then
                    errorMessages = errorMessages + " Could not delete message with index " + i.ToString + vbCrLf + tempStr + vbCrLf
                    allIsGood = False
                End If
            Next
        Catch ex As InvalidOperationException
            errorMessages = errorMessages + " Could not delete messages: " & vbCrLf & Err.ToString + vbCrLf
            allIsGood = False
            Exit Sub
        End Try
    End Sub

    Private Sub disconnect(ByRef allIsGood As Boolean, ByVal numberOfMessages As Integer, ByRef errorMessages As String)
        
        Dim data As String = "QUIT"
        Dim szData() As Byte = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
        netStrm.Write(szData, 0, szData.Length)
        Dim tempStr As String = rdStrm.ReadLine()
        If tempStr.StartsWith("-ERR") Then
            errorMessages = errorMessages + " Could not disconnect from server " + tempStr + vbCrLf
            allIsGood = False
        End If
        Try
            rdStrm.Close()
            netStrm.Close()
            server.Close()
        Catch ex As Exception
            errorMessages = errorMessages + " Could not disconnect from server " + ex.ToString + vbCrLf
            allIsGood = False
        End Try
        
    End Sub

    Private Sub writeLogFile(ByVal errorMessages As String)

        Dim logFileSplit() As String = errorMessages.Split(vbCrLf)

        If System.IO.Directory.Exists(ErrorLogLocation) Then
        Else
            System.IO.Directory.CreateDirectory(ErrorLogLocation)
        End If
        Dim logFile As New System.IO.StreamWriter(ErrorLogLocation + "\" + Replace(Replace(Replace(System.DateTime.Now.ToString, "/", "-"), ":", "-"), " ", "_") + ".txt")

        Dim i As Integer = 0
        For i = 1 To logFileSplit.Length - 1 Step i + 1
            logFile.WriteLine(logFileSplit(i).ToString)
        Next
        logFile.Close()

    End Sub

End Class

Open in new window

0
Comment
Question by:David11011
  • 6
  • 3
10 Comments
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 37000927
I didn't know that POP waited until the session was closed before actually deleting the messages.  But, assuming that to be true, lets look at the deleteMessages sub .  You are sending
DELE 5
each iteration of the loop, but if the messages don't get deleted immediately, I think this means that only one message (i.e. #5) is ever going to get marked for deletion.  This is just a guess, though, I never played with POP coding myself.
0
 
LVL 70

Expert Comment

by:Éric Moreau
ID: 37000940
I use this component to manage emails: http://www.lesnikowski.com/mail/
0
 
LVL 2

Author Comment

by:David11011
ID: 37000973
crap! that DELE 5 isnt' actually in the code. I just put that in there while I was testing it so I could watch it break. ignore that. Normally it says
data = DELE " & i.ToString & vbCrLf
I just forgot to change it back before I posted my code :)


0
Get quick recovery of individual SharePoint items

Free tool – Veeam Explorer for Microsoft SharePoint, enables fast, easy restores of SharePoint sites, documents, libraries and lists — all with no agents to manage and no additional licenses to buy.

 
LVL 31

Accepted Solution

by:
LeeDerbyshire earned 2000 total points
ID: 37001073
Well, that /does/ throw a different light on things :-)  Just a couple of things before I shoot off for home (I live in the UK).

Enable and then check POP protocol logging - to see if the commands reach the server, and how it reacts.

Try a telnet session, and see if the mails get deleted from there.

In case the messages are deleted immediately (i.e. as soon as DELE is sent), it is best to start at the end, rather than the beginning, otherwise half of the messages don't get deleted.  I learned that one the hard way.

For i = numberOfMessages To 1 Step - 1

This looks odd, anyway:
For i = 1 To numberOfMessages Step i + 1
isn't the step value going to be changed each time the loop iterates?  I don't know whether it will step 1, 2, or variably.
0
 
LVL 2

Author Comment

by:David11011
ID: 37001100
The code is so close to working I'd rather not scrap it all and rewrite something that uses somebody else's component.
0
 
LVL 2

Author Comment

by:David11011
ID: 37001150
Thanks, I'll try the telnet thing and POP protocol logging and see if I can see anything fishy going on.

The "Step i + 1" works the same as "Step + 1". I don't know why I do it that way. It's just the way I've always done it since way back in Quick Basic lol.
0
 
LVL 2

Author Comment

by:David11011
ID: 37002296
Ok, so I connect to the POP3 server via telnet and ran the command and everything worked fine.
I was still puzzled because the commands that I manually ran entered in the telnet session are the same commands that my program was sending.

After some head scratching I found the solution.

I put a carriage return line feed at the end of my QUIT command and it worked!

Dim data As String = "QUIT" + vbCrlf

I guess that it needed that extra return to submit the quit statement properly.
0
 
LVL 2

Author Comment

by:David11011
ID: 37002385
Now I'm dealing with another problem.

When I telnet only allows a screen width of, I think, 70 character and then wraps to the next line. The problem with this is that the emails are returning with one or two words on a line because it wraps the text.

Any ideas on how to get this formatted properly?

I'm splitting the body of text using "\n" as my delimiter. Then loop through the split array and writing each line to a text file

Dim splitBody() As String = body.Split("\n")
Dim fileToWrite As New System.IO.StreamWriter(saveFilesLocation + orderNum + ".txt")
        Dim i As Integer = 0
            For i = 0 To splitBody.Length - 1 Step i + 1
                fileToWrite.WriteLine(splitBody(i) + vbCrLf)
            Next

I don't know if I should modify the commands that I'm sending to the mailserver so that it doesn't create a new line with lines that have more than 70 characters or to modify how I am splitting up the returned string.

I've attached an example of one of the text files the program creates. W00242970000.txt
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 2000 total points
ID: 37002863
I think what you have encountered is known as 'byte-stuffing'.  It's mentioned in the POP3 RFC 1255, but not in any way that helps much.  If you search for it, you should find answers like this one:
http://www.google.com/support/forum/p/gmail/thread?tid=20a50ade3e8e820d
0
 
LVL 2

Author Closing Comment

by:David11011
ID: 37009444
Thanks for your help Lee. You put me down the right path to getting thing solved.

I ended up using POP3 to pull down the emails.
I programmed some logic into the application so that it can determine if each response line should be on it's own line or if it should be appended onto the previous line in the string.

The program went from what I thought was going to be a pretty small piece of software to a beast of a program. But, after days of coding I've got it all finished and it's working. thanks again.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article describes Top 9 Exchange troubleshooting utilities that every Exchange Administrator should know. Most of the utilities are available free of cost. List of tools that I am going to explain in this article are:   Microsoft Remote Con…
In this article, I will demonstrate that how to do a PST migration from Exchange Server to Office 365. This method allows importing one single PST, or multiple PST's at once.
Introduction to Processes
Whether it be Exchange Server Crash Issues, Dirty Shutdown Errors or Failed to mount error, Stellar Phoenix Mailbox Exchange Recovery has always got your back. With the help of its easy to understand user interface and 3 simple steps recovery proced…
Suggested Courses

580 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question