[C#] POP3 Email Browser

Drucken
( 5 Votes )
Hauptkategorie: Programmieren Kategorie: C#
Erstellt am 27.11.2012 Zuletzt aktualisiert am 28.11.2012 Geschrieben von Jonny132
Leider bietet .NET nicht von Haus aus an, Emails konfortabel von eineim POP3 Server zu laden.
Deshalb muss man sich selber etwas mit TCP und Streams auseinandersetzten.

In diesem Tutorial zeige ich euch wie ihr euch selber einen Emailbrowser mittels POP3 Server nachbauen könnt.

Dazu erstellen wir zuerst ein neues Forms-Projekt mit einer ListBox um die Emails aufzulisten, 2 Labels für Sender und Betreff, eine Textbox für den Inhalt (MultiLine = true) und einem Button welcher das Runterladen der Emails vom POP3 Server startet.

Somit hätten wir die Grundlegende Oberfläche um die POP3 Emails anzeigen zu lassen.

Nun wechseln wir in die Codeansicht, in der wir uns zuerst eine Email-Klasse erstellen, die uns den Umgang mit den Emails erleichtert.

Die Email-Klasse beinhaltet 4 Eigenschaften:
  • Sender - Enhält den Sender der Email
  • Subject - Enhält den Betreff der Email
  • Body - Enthält den Inhalt der Email
  • SenderAndSubject - Ist eine ReadOnly Eigenschaft die den Sender und das Subject verkettet damit es in der ListBox später gleich klar ist, um welche Email vom POP3 - Server es sich handelt.


Desweiteren erstellen wir einen Konstruktor, welcher uns als Parameter die Email als Quellcode entgegennimmt (Plain). Aus diesem Plain-Text können wir uns dann die benötigten Daten aus dem Header und aus dem Body herausholen.

Email-Klasse:

  public class Email
  {
    public string Sender { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }

    public string SenderAndSubject
    {
      get
      {
        return Sender + ": " + Subject;
      }
    }

    public Email(string plainEmailText)
    {
      string[] headerLines =
          plainEmailText.Substring(0,
              plainEmailText.IndexOf(Environment.NewLine + Environment.NewLine)).Split(Environment.NewLine.ToCharArray());

      Sender = headerLines.First(s => s.StartsWith("From")).Substring(6);
      Subject = headerLines.First(s => s.StartsWith("Subject")).Substring(9);

      Body = plainEmailText.Substring(plainEmailText.IndexOf(Environment.NewLine + Environment.NewLine));

    }
  }

Um den Header vom Body zu unterscheiden, müssen wir uns etwas mit dem Format auskennen. Der Trick dabei ist, dass dazwischen immer ein doppeltes NewLine vorkommt und somit können wir an dieser Stelle Splitten.

Nun kommt der Interessante Teil. Das holen der Emails vom POP3 Server im Klick-Ereignis des Buttons.
Dazu benötigen wir zuerst eine List<> Objekt das unsere Emails beinhaltet. Dieses können wir dann an unsere Controls bzw. unsere Oberfläche mittels Databinding binden. 
Darüber hinaus benötigen wir jeweils ein Using für ein TcpClient-, NetworkStream- und StreamReader-Objekt.
Das Ganze packen wir noch in einen Try-Catch Block um einen möglichen Fehler abzufangen.

Databinding & Using-Statements:
    private void button1_Click(object sender, EventArgs e)
    {
      try
      {
        List<Email> mails = new List<Email>();

        using (TcpClient server = new TcpClient("host", 110))
        {
          if (server.Connected)
          {
            using (NetworkStream stream = server.GetStream())
            {
              using (StreamReader reader = new StreamReader(stream))
              {
                 // Hier kommt die eigentliche Kommunikation mit dem POP3 Server
              }
            }
          }
        }

        BindingSource bs = new BindingSource(mails, "");

        lbEmails.DataSource = bs;
        lbEmails.DisplayMember = "SenderAndSubject";

        lblSubject.DataBindings.Add("Text", bs, "Subject");
        lblSender.DataBindings.Add("Text", bs, "Sender");
        tbContent.DataBindings.Add("Text", bs, "Body");
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.ToString());
      }
    }

Wie ihr seht, erwartet der Konstruktor der TcpClient den Host und den Port.
Um zu überprüfen ob der POP3 Server verbunden ist, können wir die Connected-Eigenschaft abfragen.

Da ein POP3-Server immer mithilfe von Befehlen arbeitet, habe ich mir eine kleine Hilfsfunktion geschrieben, welche einen Befehl absetzt und überprüft ob die Antwort des Servers OK ist und diese als Boolschen Wert zurückgibt.

Hilfsfunktion SendCommand():
    private bool SendCommand(NetworkStream stream, StreamReader reader, string command)
    {
      byte[] commandBytes = Encoding.ASCII.GetBytes(command + Environment.NewLine);
      stream.Write(commandBytes, 0, commandBytes.Length);

      return reader.ReadLine().Contains("+OK");
    }

Der POP3-Server erwartet immer einen Befehl mit abschliessendem Zeilenumbruch.
Da ein Stream immer auf Byteebene arbeitet, müssen wir den Befehl mittels Encoding in ein ByteArray umwandeln.
Enhält die Antwort vom Server ein OK, so wurde der Befehl erfolgreich durchgeführ und wir können mit der Verarbeitung des Codes weitermachen.

Nun kommen wir wieder zum eigentlichen Code - Dieser gehört, gleich wie der vorige Code, in das Button - Click Ereignis, wo der Kommentar steht und wurde im Tutorial zur Übersicht getrennt.

Kommunikation mit dem Server:
                if (SendCommand(stream, reader, "USER username"))
                {
                  if (SendCommand(stream, reader, "PASS password"))
                  {
                    if (SendCommand(stream, reader, "LIST"))
                    {
                      string emailData;
                      while ((emailData = reader.ReadLine()) != "." && mails.Count <= 5)
                      {
                        int mailID = -1;

                        if (emailData.IndexOf(" ") > 0 && int.TryParse(emailData.Substring(0, emailData.IndexOf(" ")), out mailID))
                        {
                          StreamReader mailReader = new StreamReader(stream);


                          SendCommand(stream, mailReader, "RETR " + mailID);
                          string plainEmailLine;
                          StringBuilder plainEmailLines = new StringBuilder();
                          while ((plainEmailLine = mailReader.ReadLine()) != ".")
                          {
                            plainEmailLines.AppendLine(plainEmailLine);
                          }
                          mails.Add(new Email(plainEmailLines.ToString()));
                        }
                      }

                    }
                    else
                    {
                      MessageBox.Show("Verbindung zum Server wurde verweigert");
                    }
                  }
                }

Zuerst müssen wir uns am POP3-Server authentifizieren.
Dies geschieht in dem wir zuerst den User und anschliessen das zugehörige Passwort per Befehl abschicken und die Antwort auswerten.

Mithilfe des LIST-Befehl, bekommen wir eine Liste der EmailId's über welche wir iterieren können. Damit wir nicht das Ganze Postfach abholen, habe ich die Ausgabe mittels Count im Code auf fünf beschränkt.

Zu guter letzt wird noch der RETR-Befehl mit zugehöriger EmailId ausgeführt, für welchen wir eine neue Reader instanz brauchen. Dieser lädtd die Email als Plaintext nun zur Gänze vom POP3-Server. Genau diesen Plaintext können wir nun an unseren Konstukter der Email-Klasse übergeben und so ein neues Email-Objekt erstellen. 

Oberfläche:
POP3 Email Browser


 

 

  • Bozkurt

    schrieb am 2013-04-25 20:28:36

    Guten Tag,

    Danke fürs Tutorial.
    Doch eine Bitte habe ich an dich, ich habe versucht es nach zu programmieren, hat auch so einigermaßen geklapt aber mir werden die Variablen "stream" und "mail" und "reader" beim Abschnitt "Kommunikation mit dem Server:" als Fehler angezeigt und ich weiß leider nicht mit was für ein Datentyp diese programmiert wurden.
    Dachte du kannst mir helfen :)

    Mit freundlichen Grüßen

    Bozkurt

    Auf Kommentar antworten

    • Jonny132

      schrieb am 2013-04-26 11:08:10

      Hallo Bozkurt,

      wenn man sich das Tutorial durchliest erübrigt sich die Frage eigentlich:

      "Nun kommen wir wieder zum eigentlichen Code - Dieser gehört, gleich wie der vorige Code, in das Button - Click Ereignis, wo der Kommentar steht und wurde im Tutorial zur Übersicht getrennt."

      Auf Kommentar antworten

Veröffentlichen Sie ihre Kommentare ...