milhero 0 Light Poster

Hi Professionals,

I found these tutorials and codes regarding 'Retrieve E-Mail Through POP3' on an e-book entitled 'Microsoft Visual Basic .NET Programmer's Cookbook'. I understand what each functions/codes are but how do i design the GUI/interface to fit the codes?

Please advise. Thank you in advance.

Best Regards,
Md Azmil

Problem

You want to retrieve messages from a POP3 mail server.

Solution

Create a dedicated class that sends POP3 commands over a TCP connection.

Discussion

POP3 is a common e-mail protocol used to download messages from a mail server. POP3, like many Internet protocols, defines a small set of commands that are sent as simple ASCII-encoded messages over a TCP connection (typically on port 110).

Here's a listing of a typical POP3 dialogue, starting immediately after the client makes a TCP connection:

Server sends:+OK <22689.1039100760@mail.prosetech.com>
Client sends:USER <UserName>
Server sends:+OK
Client sends:PASS <Password>
Server sends:+OK
Client sends:LIST
Server sends:+OK
Server sends:<Message list terminated by a period>
Clients sends:RETR <MessageNumber>
Server sends:+OK
Server sends:<Message body terminated by a period>
Client sends:QUIT
Server sends:+OK

To add this functionality to your .NET applications, you can create a Pop3Client class that encapsulates all the logic for communicating with a POP3 server. Your application can then retrieve information about messages using the Pop3Client class. We'll explore this class piece by piece in this recipe. To see the complete code, download the recipes for this chapter in this book's sample files.

The first step is to define a basic skeleton for the Pop3Client class. It should store a TcpClient instance as a member variable, which will be used to send all network messages. You can also add generic Send and ReceiveResponse messages, which translate data from binary form into the ASCII encoding used for POP3 communication.

Public Class Pop3Client
    Inherits System.ComponentModel.Component
   
    ' The internal TCP connection.
    Private Client As New TcpClient()
    Private Stream As NetworkStream
   
    ' The connection state.
    Private _Connected As Boolean = False
    Public ReadOnly Property Connected() As Boolean
        Get
            Return _Connected
        End Get
    End Property
   
    Private Sub Send(ByVal message As String)
        ' Send the command in ASCII format.
        Dim MessageBytes() As Byte = Encoding.ASCII.GetBytes(message)
        Stream.Write(MessageBytes, 0, MessageBytes.Length)
   
        Debug.WriteLine(message)
    End Sub
   
    Private Function GetResponse() As String
        ' Build up the response string until the line termination
        ' character is found.
        Dim Character, Response As String
        Do
            Character = Chr(Stream.ReadByte()).ToString()
            Response &= Character
        Loop Until Character = Chr(13)
   
        Response = Response.Trim(New Char() {Chr(13), Chr(10)})
        Debug.WriteLine(Response)
        Return Response
    End Function
   
    ' (Other code omitted.)
   
End Class

You'll notice that the Pop3Client is derived from the Component class. This nicety allows you to add and configure an instance of the Pop3Client class at design time using Microsoft Visual Studio .NET.

You can also add constants for common POP3 commands. One easy way to add constants is to group them in a private class nested inside Pop3Client, as shown here:

' Some command constants.
Private Class Commands
    ' These constants represent client commands.
    Public Const List As String = "LIST" & vbNewLine
    Public Const User As String = "USER "
    Public Const Password As String = "PASS "
    Public Const Delete As String = "DELE "
    Public Const GetMessage As String = "RETR "
    Public Const Quit As String = "QUIT" & vbNewLine
   
    ' These two constants represent server responses.
    Public Const ServerConfirm As String = "+OK"
    Public Const ServerNoMoreData As String = "."
End Class

The next step is to create a basic method for connecting to the POP3 server and disconnecting from it. Because Pop3Client derives from Component, it indirectly implements IDisposable. Therefore, you can also override the Dispose method to ensure that connections are properly cleaned up when the class is disposed.

Public Sub Connect(ByVal serverName As String, ByVal userName As String, _
  ByVal password As String)
    If Connected Then Me.Disconnect()
   
    ' Connect to the POP3 server
    ' (which is almost always at port 110).
    Client.Connect(serverName, 110)
    Stream = Client.GetStream()
   
    ' Check if connection worked.
    CheckResponse(GetResponse())
   
    ' Send user name.
    Send(Commands.User & userName & vbNewLine)
   
    ' Check response.
    CheckResponse(GetResponse())
   
    ' Send password.
    Send(Commands.Password & password & vbNewLine)
   
    ' Check response.
    CheckResponse(GetResponse())
   
    _Connected = True
End Sub
   
Public Sub Disconnect()
    If Connected Then
        Send(Commands.Quit)
        CheckResponse(GetResponse())
        _Connected = False
    End If
End Sub
   
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then Disconnect()
    MyBase.Dispose(disposing)
End Sub

	Note 	

Some mail servers will not allow the password to be transmitted in clear text. In this case, you will need to manually encrypt the password information first using the appropriate algorithm before you submit it to the Pop3Client class.

The Pop3Client class uses a private CheckResponse procedure, which verifies that the server's message is the excepted confirmation and throws an exception if it isn't.

Private Sub CheckResponse(ByVal response As String)
    If Not (response.Substring(0, 3) = Commands.ServerConfirm) Then
        Client.Close()
        _Connected = False
        Throw New ApplicationException("Response " & response & _
          " not expected.")
    End If
End Sub

The only remaining step is to implement three higher-level methods: GetMessageList, which the client calls to retrieve a list of message headers, GetMessageContent, which the client calls to retrieve the body of a single message, and DeleteMessage, which is typically used to remove a message after its content is downloaded.

To support the GetMessageList method, you need to create a simple class for storing message header information, which includes a message number and size in bytes.

Public Class MessageHeader
   
    Private _Number As Integer
    Private _Size As Integer
   
    Public ReadOnly Property Number() As Integer
        Get
            Return _Number
        End Get
    End Property
   
    Public ReadOnly Property Size() As Integer
        Get
            Return _Size
        End Get
    End Property
   
    Public Sub New(ByVal number As Integer, ByVal size As Integer)
        Me._Number = number
        Me._Size = size
    End Sub
   
End Class

The GetMessageList method returns an array of MessageHeader objects. When the server returns a period (.) on a separate line, the list is complete.

Public Function GetMessageList() As MessageHeader()
    If Not Connected Then Throw New _
      InvalidOperationException("Not connected.")
   
    Send(Commands.List)
    CheckResponse(GetResponse())
   
    Dim Messages As New ArrayList()
    Do
        Dim Response As String = GetResponse()
   
        If Response = Commands.ServerNoMoreData Then
            ' No more messages.
            Return CType(Messages.ToArray(GetType(MessageHeader)), _
              MessageHeader())
        Else
            ' Create an EmailMessage object for this message.
            ' Include the header information.
            Dim Values() As String = Response.Split()
            Dim Message As New MessageHeader(Val(Values(0)), Val(Values(1)))
   
            Messages.Add(Message)
        End If
    Loop
End Function

To retrieve the information for a single message, the client calls GetMessageContent with the appropriate message number. The message content includes headers that indicate the sender, recipient, and path taken, along with the message subject, priority, and body. A more sophisticated version of the Pop3Client might parse this information into a class that provides separate properties for these details.

Public Function GetMessageContent(ByVal messageNumber As Integer) As String
    If Not Connected Then Throw New _
      InvalidOperationException("Not connected.")
   
    Send(Commands.GetMessage & messageNumber.ToString() & vbNewLine)
    CheckResponse(GetResponse)
    Dim Line, Content As String
   
    ' Retrieve all message text until the end point.
    Do
        Line = GetResponse()
        If Line = Commands.ServerNoMoreData Then
            Return Content
        Else
            Content &= Line & vbNewLine
        End If
    Loop
End Function

Finally DeleteMessage removes a message from the server based on its message number.

Public Sub DeleteMessage(ByVal messageNumber As Integer)
    If Not Connected Then Throw New _
      InvalidOperationException("Not connected.")
   
    Send(Commands.Delete & messageNumber.ToString() & vbNewLine)
    CheckResponse(GetResponse())
End Sub

You can test the Pop3Client class with a simple program such as the following one, which retrieves all the messages for a given account:

Public Module Pop3Test
   
    Public Sub Main()
        ' Get the connection information.
        Dim Server, Name, Password As String
        Console.Write("POP3 Server: ")
        Server = Console.ReadLine()
        Console.Write("Name: ")
        Name = Console.ReadLine()
        Console.Write("Password: ")
        Password = Console.ReadLine()
        Console.WriteLine()
   
        ' Connect.
        Dim POP3 As New Pop3Client()
        POP3.Connect(Server, Name, Password)
   
        ' Retrieve a list of message, and display the corresponding content.
        Dim Messages() As MessageHeader = POP3.GetMessageList()
        Console.WriteLine(Messages.Length().ToString() & " messages.")
   
        Dim Message As MessageHeader
        For Each Message In Messages
            Console.WriteLine(New String("-"c, 60))
            Console.WriteLine("Message Number: " & Message.Number.ToString())
            Console.WriteLine("Size: " & Message.Size.ToString())
            Console.WriteLine()
            Console.WriteLine(POP3.GetMessageContent(Message.Number))
            Console.WriteLine(New String("-"c, 60))
            Console.WriteLine()
        Next
   
        Console.WriteLine("Press Enter to disconnect.")
        Console.ReadLine()
        POP3.Disconnect()
    End Sub
   
End Module

The output for a typical session is as follows:

POP3 Server: mail.server.com
Name: matthew
Password: opensesame
   
1 messages.
------------------------------------------------------------------------------
Message Number: 1
Size: 1380
   
Return-Path: <someone@somewhere.com>
Delivered-To: somewhere.com%someone@somewhere.com
Received: (cpmta 15300 invoked from network); 5 Dec 2002 06:57:13 -0800
Received: from 66.185.86.71 (HELO fep01-mail.bloor.is.net.cable.rogers.com)
  by smtp.c000.snv.cp.net (209.228.32.87) with SMTP; 5 Dec 2002 06:57:13 -0800
X-Received: 5 Dec 2002 14:57:13 GMT
Received: from fariamat ([24.114.131.60])
          by fep01-mail.bloor.is.net.cable.rogers.com
          (InterMail vM.5.01.05.06 201-253-122-126-106-20020509) with ESMTP
          id <20021205145711.SJDZ4718.fep01- mail.bloor.is.net.cable.rogers.com@fariamat>
          for <someone@somewhere.com>; Thu, 5 Dec 2002 09:57:11 -0500
Message-ID: <004c01c29c6f$186c5150$3c837218@fariamat>
From: <someone@somewhere.com>
To: <someone@somewhere.com>
Subject: Test Message
Date: Thu, 5 Dec 2002 10:00:48 -0500
MIME-Version: 1.0
Content-Type: text/plain;
        charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 6.00.2600.0000
X-MIMEOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
X-Authentication-Info: Submitted using SMTP AUTH LOGIN at fep01-- 
mail.bloor.is.net.cable.rogers.com from [24.114.131.60] at
Thu, 5 Dec 2002 09:57:11 -0500
Status: RO
X-UIDL: Pe9pStHkIFc7yAE
   
Hi! This is a test message!
------------------------------------------------------------------------------
   
Press Enter to disconnect.
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.