deleting emails via POP3

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

LVL 2
David11011Asked:
Who is Participating?
 
LeeDerbyshireCommented:
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
 
LeeDerbyshireCommented:
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
 
Éric MoreauSenior .Net ConsultantCommented:
I use this component to manage emails: http://www.lesnikowski.com/mail/
0
Problems using Powershell and Active Directory?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

 
David11011Author Commented:
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
 
David11011Author Commented:
The code is so close to working I'd rather not scrap it all and rewrite something that uses somebody else's component.
0
 
David11011Author Commented:
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
 
David11011Author Commented:
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
 
David11011Author Commented:
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
 
LeeDerbyshireCommented:
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
 
David11011Author Commented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.