DevTrain Startseite Advanced Developers Conference vom 14.-15. Februar 2011  
  
  
SUCHEN:  
ARTIKEL ONLINE: 525   

Kategorien
.NET
Datenbanken
Web
XML

Allgemein
Camp
Foren
Events
Persönliche Einstellungen
Registrieren
Prämien Shop
Kontakt
Impressum
Über DevTrain

Autoren


   Autor: Tobi Ulm Artikel Drucken
        
POP3 Client mit .NET

Häufig wird mir die Frage gestellt wie man per Sockets mit Standardservern wie POP3 kommuniziert. Aus diesem Grund habe ich  ein einfaches Beispiel erzeugt welches über den TCPClient mit einem POP3 Server kommuniziert und E-Mails vom POP3 Server  abruft.

POP3 ist ein Internetstandardprotokoll welches mit einem ganz geringem ASCII Befehlssatz auskommt wobei die Befehle über das  TCP Protokoll versendet werden.
Um diese Befehle nicht jedes Mal eintippen zu müssen habe ich eine innere Klasse in der POP3 Klasse welche den Minimum  Befehlssatz des POP3 Protokolls darstellt:

private class Commands {
 #region "datamember"
 public const string Delete = "DELE ";
 public const string GetMessage = "RETR ";
 public const string List = "LIST\r\n";
 public const string Password = "PASS ";
 public const string Quit = "QUIT\r\n";
 public const string ServerConfirm = "+OK";
 public const string ServerNoMoreData = ".";
 public const string User = "USER ";
 #endregion
 #region "ctor"
 private Commands() {
 }
 #endregion
};

In der Klasse Pop3Client müssen als erstes die zwei wichtigen Instanzvariablen
private TcpClient m_client = new TcpClient();
private NetworkStream m_stream;
deklariert werden. m_client ist unsere TCP Verbindung zum POP3 Server. Ob man den TcpClient gleich instanziert ist  Geschmackssache. m_stream ist der Datenstrom welcher vom POP3 Server hin und zurück gesendet wird.

Als nächstes benötigen wir Funktionen die uns die binären Daten in ASCII Format für die Übertragung umwandeln:

private void Send(string message ){
 // Send the command in ASCII format.
 byte[] messagebytes = Encoding.ASCII.GetBytes(message);
 this.m_stream.Write(messagebytes, 0, messagebytes.Length);
}
private string GetResponse(){
 string text3 = string.Empty;
 char ch1;
 System.Text.StringBuilder strBld = new StringBuilder();
 do {
  ch1 = System.Convert.ToChar(this.m_stream.ReadByte());
  strBld.Append(ch1.ToString());
 } while (String.Compare(ch1.ToString(), "\r", false, CultureInfo.CurrentCulture) != 0);
 char[] chArray1 = new char[2] { '\r', '\n' };
 text3 = strBld.ToString();
 text3 = text3.Trim(chArray1);
 return text3;
}

Der nächste Schritt ist nun die Verbindung zum POP3 Server herzustellen und wieder zu schließen:

public void Connect(string serverName, string userName, string password) {
if (this.m_connected) {
 this.Disconnect();
}
try {
 this.m_client.Connect(serverName, 110);
 this.m_stream = this.m_client.GetStream();
 this.CheckResponse(this.GetResponse());
 this.Send(Commands.User + userName + "\r\n");
 this.CheckResponse(this.GetResponse());
 this.Send(Commands.Password + password + "\r\n");
 this.CheckResponse(this.GetResponse());
 this.m_connected = true;
}
catch (Exception e) {
 this.Disconnect();
 throw new ApplicationException(e.Message, e);
}
}

Bitte beachten Sie hier dass uns der POP3 Server uns ständig Rückantworten zurückgibt, aus diesem Grund wird nachdem der  Client über die m_client.Connect("", int) Methode verbunden wird der Datenstrom ausgelesen und überprüft (  this.CheckResponse(string) )ob der Server die Anfrage korrekt verarbeiten konnte. Außerdem muss ich darauf hinweisen, dass  dies ein einfaches Beispiel ist, bei manchen POP3 Servern ist es Pflicht das Passwort verschlüsselt zu senden.

public  void Disconnect() {
 if (this.m_connected) {
  this.Send(Commands.Quit);
  this.CheckResponse(this.GetResponse());
  this.m_connected = false;
  this.m_client.Close();
 }
}

private void CheckResponse(string response) {
 if (String.Compare(response.Substring(0, 3), Commands.ServerConfirm, false, CultureInfo.CurrentCulture) != 0) {
  this.m_client.Close();
  this.m_connected = false;
  throw new ApplicationException("Response " + response + " not expected.");
 }
}

Nun folgt die eigentliche Arbeit. Wir benötigen eine Methode die uns das Postfach ausliest, d.h. die Anzahl der Nachrichten  ausliest. Standardmäßig wird das im POP3 Protokoll so definiert das die Nachricht mit einer MessageId versehen ist mit der  später die Nachricht vom Server geholt wird. Außerdem bekommen wir noch die Größe der Nachricht zurück. Diese  Metainformationen habe ich in einer eigenen Klasse MessageHeader implementiert, welche nun verwendet wird:

public MessageHeader[] GetMessageList() {
   string text1 = string.Empty;
   if (!this.m_connected) {
    throw new InvalidOperationException("Not connected.");
   }
   this.Send(Commands.List);
   this.CheckResponse(this.GetResponse());
   ArrayList list1 = new ArrayList();
   while (true) {
    text1 = this.GetResponse();
    if (string.Compare(text1, Commands.ServerNoMoreData, false, CultureInfo.CurrentCulture) == 0)

{
     return (MessageHeader[])list1.ToArray(typeof(MessageHeader));
    }
    else {
     string[] textArray1 = text1.Split(new char[0]);
     MessageHeader header1 = new MessageHeader((int)Math.Round(double.Parse(textArray1[0],

 NumberFormatInfo.CurrentInfo)),
                

(int)Math.Round(Double.Parse(textArray1[1], NumberFormatInfo.CurrentInfo)));
     list1.Add(header1);
    }
   }
  }

Nun müssen wir nur noch die Methode implementieren die eine bestimmte Nachricht vom POP3 Server liest. Dies wird wie bereits oben erwähnt über eine NachrichtenId ermöglicht.

public string GetMessageContent(int messageNumber) {
   System.Text.StringBuilder strBldContent = new StringBuilder();
   if (!this.m_connected) {
    throw new InvalidOperationException("Not connected.");
   }
   this.Send(Commands.GetMessage + messageNumber.ToString("G", NumberFormatInfo.CurrentInfo) + "\r\n");
   this.CheckResponse(this.GetResponse());
   string text1 = string.Empty;
   while (true) {
     text1 = this.GetResponse();
     if (string.Compare(text1, Commands.ServerNoMoreData, false, CultureInfo.CurrentCulture) ==

0) {
     return strBldContent.ToString();
    }
    else {
     strBldContent.Append(text1);
     strBldContent.Append("\r\n");
    }
   }
  } 

Wir lesen nun aus dem Datenstrom solange aus, bis der Server uns das OK gibt das nichts mehr nachkommt.

Normalerweise kann man in modernen POP3 Clients einstellen ob die Nachrichten nach dem Abholvorgang vom Server gelöscht werden sollen. Diese Funktionalität ist hier implementiert:

public void DeleteMessage(int messageNumber) {
   if (!this.m_connected) {
    throw new InvalidOperationException("Not connected.");
   }
   this.Send(Commands.Delete + messageNumber.ToString("G", NumberFormatInfo.CurrentInfo) + "\r\n");
   this.CheckResponse(this.GetResponse());
   
  }

Was wir nun nur noch brauchen ist ein kleines Client Programm welche unsere POP3 Klasse verwendet.

Imports Tu.Net.Pop3
Public Class Form1
'...
    Private m_pop3client As New tu.net.pop3.Pop3Client


    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Try
            Me.m_pop3client.Connect(Me.txtServername.Text, Me.txtUid.Text, Me.txtPwd.Text)
            'retrieve a list of all message
            Dim Messages() As MessageHeader = Me.m_pop3client.GetMessageList()
            Me.lblMessage.Text = Messages.Length().ToString() & " messages. You're still connected. Move your mouse over a

message id to read the message."

            Dim Message As MessageHeader
            For Each Message In Messages
                Dim strSubItem() As String = {Message.Number.ToString(), Message.Size.ToString()}
                Dim myItem As New ListViewItem(strSubItem)
                Me.ListView1.Items.Add(myItem)
            Next
        Catch ex As Exception
            MessageBox.Show(ex.ToString())
        End Try

 

    End Sub

    Private Sub ListView1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles

ListView1.SelectedIndexChanged
        If (Me.ListView1.SelectedIndices.Count <> 0) Then
            Dim messageId As Integer = Integer.Parse(Me.ListView1.SelectedItems(0).SubItems(0).Text)
            Dim strMessage As String = Me.m_pop3client.GetMessageContent(messageId)
            Me.RichTextBox1.Text = strMessage
        End If
    End Sub

    Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs)

Handles MyBase.FormClosing
        If (Me.m_pop3client.Connected) Then
            Me.m_pop3client.Disconnect()
            Me.m_pop3client.Dispose()
        End If
    End Sub
'...
End Class


DevTrain Camp - Schneller zum .NET 3.5 Developer
 
Verwandte Artikel      Verlinkte Dokumente
    Keine verknüpften Dokumente
    Keine Links vorhanden

  Erfasst am: 18.03.2005
  Gültig bis: 16.06.2005
2 Ratings
Bewertung: 50,0%
schlecht    sehr gut  

 
© Copyright 2007 ppedv AG