zurück
Autor: Hannes Preishuber
Erstellt am: 03 Apr 2003 16:59

POP3 Mailkonten mit VB .NET abfragen

Mail ist ein wichtiger Bestandteil von modernen Programmen. Das Versenden von eMails funktioniert dabei über das SMTP Protokoll, für das es eine eigene Klasse im Framework gibt. Das Abholen ist schon ein bisschen komplexer. Dazu bedarf es einiger Kenntnisse der Grundlagen.

Zunächst eine kurze Einweisung in die Funktionsweise. Ein POP3 (Post Office Protokoll) Server wird über einen einfachen Befehlssatz gesteuert. Der Verbindungsaufbau erfolgt über TCP/IP und einen Port (fast immer 110). So kann man auch über Telnet mails abholen.
Hier die Syntax für Windows 2000. Eingaben sind Fett.

telnet mailserver 110
USER benutzer
+OK
PASS passwort

+OK
STAT
1 1234
RETR 1
dsfdsfdsf
....

Mit STAT wird der Staus der Mailbox angezeigt. Dabei werden zwei Zahlen zurückgegeben. Die erste liefert die Anzahl der Mails und die zweite die gesamte Größe.
Über RETR mit dem Zusatz Mail Nr kann das Mail gelesen werden. Ein anschließendes DELE mit Nr des Mails löscht dieses. Dabei werden die Mails von den meisten Mail Server erst endgültig gelöscht, wenn die Verbindung mit Close geschlossen wird.

Wie man aus der Verwendung von Telnet erkennen kann, ist das POP3 Protokoll keine Geheimnis. Die Befehle werden im ASCII Format übertragen und mit einem Zeilenumbruch abgeschlossen.

Dieses lässt sich in VB6 mit der Socket Klasse erledigen. In VB.NET gibt’s dazu die Socket Klassen. Deshalb wird der  Namespaces System.Net.Sockets eingebunden. Als nächstes wird mit der Funktion TCPClient einen Verbindung zum Server und Port hergestellt.
Für den Lese  und Schreib Zugriff auf die Daten werden Streams verwendet. Den Datenstrom wird per Getstream referenziert. Eine Besonderheit ist das auslesen und konvertieren von dynamischen Rückgabedaten. Eigentlich sollte man einen Buffer definieren und dann mit einer Read Methode diesen füllen. Da die Größe nicht bekannt ist, müsst Byteweise gelesen werden.
In .NET geht das über die Streamreader Klasse viel eleganter. Deshalb holen wir uns eine Instanz vom Stream mit dem Streamreader.
Damit die beiden Handles in der Sub Helper Funktion nutzbar sind, definieren wir diese als Eigenschaft der Klasse (Stream und sr)

Die Hilfsklasse Sendcommand macht für uns die Schmutzarbeit und schickt die Befehle an den POP 3 Server. Als Rückgabe erhalten wir die Antwort des Servers als String.
Weil jedes Kommando mit einem Zeilenumbruch abgeschlossen sein muss, hängen wir per VB Konstante diesen an.
Für das senden stellen wir einen Byte Buffer als Array bereit. Den machen wir so groß wie der Sendestring eben ist.
Und dann schreiben wir schon die Daten  per write raus.

Nun kommt ein kleiner Trick. Der Streamreader hat ein Gedächtnis z.B. in Punkto Leseposition. Deshalb ist es am einfachsten den Reader für jeden Lesevorgang komplett neu zu setzen. Dann lässt man eine Schleife solange laufen bis keine Daten mehr kommen. Die Funktion Peek ist dafür in der Schleife das Prüfkriterium. Der eigentliche Lesevorgang wird über Readline des Streamreaders ausgelöst, dabei werden die Zeichenketten per Stringbuilder zusammengesetzt. Da die Daten oft nicht schnell genug kommen um die Systembuffer zu füllen, ist ein Wait eingebaut. Die Funktion heißt dazu Sleep und ist in der Thread Klasse enthalten. Der Namespace dazu ist System Threading. Hier zeigt sich auch, das VB.NET Threading per default unterstützt. Am Schluss wird das Stringbuilder Objekt wieder in einen String umgewandelt und zurück geschickt.

Dann geht alles ganz einfach. Einfach die Kommandos der Reihe nach wegschicken.

Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.io
Imports System.Threading


Public Class Form1
    Inherits System.Windows.Forms.Form
    Public stream As NetworkStream
    Public sr As StreamReader

    Private Sub cmdPOPen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPOPen.Click
         Dim server As String = "servername"
        Dim user As String = "benutername"
        Dim password As String = "passwort"
        Dim message As String
        Dim send As String
        Dim client As New TcpClient(server, 110)
        stream = client.GetStream()
        sr = New StreamReader(stream)
        txtResponse.Text += sendCommand("?")
        txtResponse.Text += sendCommand("USER " + user)
        txtResponse.Text += sendCommand("PASS " + password)
        txtResponse.Text += sendCommand("STAT" + vbCrLf)
        txtResponse.Text += sendCommand("RETR 1" + vbCrLf) 'hole erstes Mail
        txtResponse.Text += sendCommand("QUIT" + vbCrLf)
    End Sub
    Private Function sendCommand(ByVal send As String) As String
        send += vbCrLf
        Dim data As [Byte]() = Encoding.ASCII.GetBytes(send)
        stream.Write(data, 0, data.Length)
        sr = New StreamReader(stream)
        Dim buffer As New StringBuilder
        Do While sr.Peek() > 0
            Thread.Sleep(100)
            buffer.Append(sr.ReadLine + vbCrLf)
        Loop
        Return buffer.ToString
    End Function
End Class


Nie vergessen offene Connections oder Files und ähnliches mit Close zu schliessen. Ansonsten macht das der Garbage Collector erst ein gutes Stück später.

Dabei ist es völlig ohne Belang ob wie in diesem Beispiel ein Windows Client mit einer Textbox die Daten anzeigt oder eine Website. 
Auch die Verwendung eines Webservices bietet sich an um z.B. einem Pocket PC die Daten zu liefern.

Unter VB 6 wird dies mit dem Winsock Control gemacht. Dabei ist die Handhabung beinahe identisch.


© Copyright 2008 ppedv AG