none
IMAP / POP3, mit SSL, Mails vom Server abrufen RRS feed

  • Frage

  • Guten Abend liebe Gemeinde,

    ein frohes Neues vorneweg.

    Vorgeschichte:
    Ich arbeite der Zeit an einem kleinen Programm, welches sich über SSL zu einem IMAP / POP3 Server verbinden soll.

    Das Problem:
    Ich bekommen keinen Stream (weder IO-Stream, NetworkStream noch SslStream) zustande, durch den ich Befehle an den Server senden und dessen Antworten empfangen kann.
    - IO-Stream ermöglicht schreiben, Server reagiert aber nicht darauf
    - NetworkStream ermöglicht schreiben, Server reagiert aber nicht darauf
    - SslStream ermöglicht weder schreiben noch lesen == tot

    Weiteres:
    Ich habe schon diverse (ca 10) Open Source Libraries ausprobiert, welche alle von sich behaupteten IMAP mit SSL beherrschen zu können.
    Keine Einzige davon hat bisher das Verbinden mit dem Server zustande bekommen, geschweige denn mir dessen Mailbox un deren Inhalt wiedergeben können.
    Vielleicht stimmt auch die Servereinstellung nicht, doch da man über Outlook ein SAMP/POP3 Konto anlegen kann, sollte es aber eigentlich funktionieren.

    Code:

    System.Net.Sockets.TcpClient tcpCLient;
    
    private void ButtonStart_Click(object sender, EventArgs e)
    {
       tcpCLient = new System.Net.Sockets.TcpClient();
       tcpCLient.ReceiveTimeout = 30000;
       tcpCLient.SendTimeout = 30000;
       tcpCLient.Connect(TextBoxServer.Text, int.Parse(TextBoxImapSslPort.Text));
    
       System.Net.Security.SslStream sslStream;
       if (tcpCLient.Connected)
       {
          System.Net.Sockets.NetworkStream stream = tcpCLient.GetStream();
          // sslStream = new System.Net.Security.SslStream(stream);
    
          stream.WriteTimeout = 30 * 1000;
          stream.ReadTimeout = 30 * 1000;
    
          string command = "A001 LOGIN " + TextBoxUsername.Text + " " + TextBoxPassword.Text + "\n";
    
          System.IO.StreamWriter writer = new System.IO.StreamWriter(stream);
          writer.Write(command);
    
          byte[] buffer = ASCIIEncoding.ASCII.GetBytes(command); //new byte[command.Length]; 
          stream.Write(buffer, 0, buffer.Length);
    
          long iStart = System.DateTime.Now.Ticks;
          StringBuilder result = new StringBuilder();
    
          while (((System.DateTime.Now.Ticks - iStart) / 10000000) < 15)
          {
             buffer = new byte[1024];
             int readedValue = stream.Read(buffer, 0, buffer.Length);
             if (readedValue > 0)
                result.Append(readedValue);
          }
    
          if (stream != null)
             stream.Dispose();
          if (tcpCLient != null)
             tcpCLient = null;
    
          MessageBox.Show(result.ToString());
       }
    }



    Abschluss:
    Falls jemand Erfahrungen hat und/oder open source Libraries kennt welche funktionieren, dann wäre ich über seine Antwort sehr erfreut.

    Mit besten Grüßen,


    Marcus
    Dienstag, 5. Januar 2010 16:29

Antworten

  • So ich habe es nun endlich rausgefunden. ;o)

    Für alle die Lösung als C# Code:

    public class ImapObject
        {
            public ImapObject(string _serverName, int _port)
            {
                Connected = false;
    
                dictionary.Fill();
    
                serverName = _serverName;
                port = _port;
            }
    
            System.Net.Sockets.TcpClient tcpClient;
            System.Net.Sockets.NetworkStream nwStream;
            System.Net.Security.SslStream sslStream;
            StreamReader reader;
    
            ImapDictionary dictionary = new ImapDictionary();
    
            public event HaveMessage Have_Message;
    
            private string serverName = string.Empty;
            private int port = 0;
    
            private string userName = string.Empty;
            private string passWord = string.Empty;
    
            public bool Connected { get; set; }
            public bool LoggedIn { get; set; }
    
            public void Run()
            {
                tcpClient = new TcpClient(serverName, port);
    
                if (tcpClient.Connected)
                {
                    CreateStreams();
    
                    string answer = reader.ReadLine();
                    if (answer.Contains(dictionary.MyImap[ImapDictionary.MyType.ResponseOK]))
                    {
                        Connected = true;
                        Have_Message("Connect successfully.");
                    }
                    else
                    {
                        Have_Message("Incorrect credentials.");
                    }
                }
            }
    
            private void CreateStreams()
            {
                nwStream = tcpClient.GetStream();
                sslStream = new SslStream(tcpClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
                sslStream.AuthenticateAsClient(serverName);
                reader = new StreamReader(sslStream);
            }
            private void KillStreams()
            {
                tcpClient = null;
                nwStream = null;
                sslStream = null;
                reader = null;
            }
    
            private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            }
    
            public List<string> ImapCommand(ImapDictionary.MyType typeOfCommand)
            {
                return ImapCommand(typeOfCommand, string.Empty);
            }
            public List<string> ImapCommand(ImapDictionary.MyType typeOfCommand, string command)
            {
                string postData = string.Empty;
                if (command.Length > 0)
                    postData = dictionary.MyImap[typeOfCommand] + " " + command + dictionary.MyImap[ImapDictionary.MyType.CommandEol];
                else
                    postData = dictionary.MyImap[typeOfCommand] + dictionary.MyImap[ImapDictionary.MyType.CommandEol];
    
                try
                {
                    return SendAndReceive(typeOfCommand, postData);
                }
                catch (Exception ex)
                {
                    List<string> errorList = new List<string>();
                    errorList.Add(ex.ToString());
                    return errorList;
                }
            }
    
            private List<string> SendAndReceive(ImapDictionary.MyType typeOfCommand, string _command)
            {
                object locker = new object();
    
                lock (locker)
                {
                    dictionary.CommandVal++;
                    string command = dictionary.CommandIdentifier + _command;
                    byte[] bytes = Encoding.ASCII.GetBytes(command.ToCharArray());
    
                    try
                    {
                        sslStream.Write(bytes, 0, bytes.Length);
    
                        List<string> resultGroup = new List<string>();
    
                        bool dataToReadAvaible = true;
    
                        while (dataToReadAvaible)
                        {
                            string result = reader.ReadLine();
                            resultGroup.Add(result);
    
                            if (result.StartsWith(dictionary.ServerAnswerOk) ||
                                result.StartsWith(dictionary.ServerAnswerNo) ||
                                result.StartsWith(dictionary.ServerAnswerBad))
                            {
                                dataToReadAvaible = false;
                            }
                        }
    
                        return resultGroup;
                    }
                    catch (Exception ex)
                    {
                        List<string> errorList = new List<string>();
                        errorList.Add(ex.ToString());
                        return errorList;
                    }
                }
            }
    
            public delegate void HaveMessage(string message);
        }

    Viel Vergnügen, falls jemand einen IMAP Clienten selbst schreibe möchte. :o)


    Grüße, Marcus
    • Als Antwort markiert NozzNazz Montag, 11. Januar 2010 08:58
    Montag, 11. Januar 2010 08:57

Alle Antworten

  • Sorry, ich sehe Du willst Emails abrufen und nicht senden.
    Du musst eine Verbindung zum pop3 Server aufbauen.
    Vielleicht hilft Dir das Beispiel dennoch.

    Hallo Marcus,
    ich lese gerade das Buch von Klaus Löffelmann. Habe was für Dich gefunden.
    Selber aber noch nicht getestet. Würde mich interessieren, ob das geht.
    Hilft Dir das ?

    Schöne Grüße
    Ellen



    Zitat:

    HINWEIS Damit – und das sei nur der Vollständigkeit halber erwähnt – dieses Beispiel auf Ihrem System laufen kann,
    müssen Sie natürlich einen entsprechend konfigurierten SMTP-(Mail-)Server im Netzwerk zur Verfügung haben. Tragen Sie
    dann die für Sie gültigen Daten anstelle der hier im Listing abgedruckten E-Mail-Daten ein, auch die hier angegebene TCP/IP
    Nummer (192,168,0.1) müssen Sie durch die TCP/IP Nummer oder den Hostnamen (z. B. smtp.web.de) Ihres SMTP Servers
    ersetzen. Falls Sie auf SMTP-Server zugreifen müssen, die keine offene Relay-Funktion unterstützen,13 ergänzen Sie im Bedarfsfall
    noch folgende Zeile (fett im folgenden Listingauszug), mit der Sie die Anmeldeinformationen übergeben.
    .
    Catch ex As Exception
    'Beim Auftreten eines Fehlers, landet man hier.
    Dim message As New MailMessage("covers@loeffelmann.de", "klaus@loeffelmann.de", _
    "Fehler bei der Programmausfühung", ex.Message)
    Dim emailClient As New SmtpClient("192.168.0.1")
    emailClient.Credentials = New Net.NetworkCredential("Username", "Passwort")
    emailClient.Send(message)
    End Try
    .
    .
    .

    • Bearbeitet Ellen Ramcke Mittwoch, 6. Januar 2010 15:15 Korrektur
    Mittwoch, 6. Januar 2010 15:05
  • Hallo Ellen,

    leider hilft mir das Beispiel nicht weiter.

    Update:
    Ich bin jetzt so weit, das ich einen SslStream zum IMAP4ref1 Server aufbauen kann.
    Dieser Server sendet mir auch ein ""* OK Microsoft Exchange Server 2003 IMAP4rev1 server version <number> (<servername>) ready.\r\n" zurück.

    Problem:
    Jetzt stellt sich für mich das Problem, wie (mit welchen Commands, mit welcher Syntax, mit welchem Stream) muss ich den Server ansprechen.
    Soll ich dafür den SslStream weiter nutzen und in diesen schreiben/aus diesem lesen oder einen neuen Stream eröffnen?

    Der Ablauf den ich erreichen will:
    - Zum Server verbinden
    - Posteingang abrufen
    - Ungelesen Mails öffnen und deren Anhang lokal abspeichern
    - Geöffnete Mails löschen
    - Vom Server trennen

    Code:
    System.Net.Sockets.TcpClient tcpClient;
    System.Net.Security.SslStream sslStream;
    StreamReader reader;
    StreamWriter writer;
    
    private void ButtonStart_Click(object sender, EventArgs e)
            {
                KillStreams();
    
                try
                {
                        ImapSslConnect();
    
                        ImapSslSelect("Inbox");
    
                        ImapSslDisconnect();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
                finally
                {
                    KillStreams();
                }
            }
    
    private void ImapSslConnect()
            {
                tcpClient = new TcpClient(TextBoxServer.Text, int.Parse(TextBoxImapSslPort.Text));
    
                if (tcpClient.Connected)
                {
                    CreateSslStream();
                    SetStreams();
    
                    try
                    {
                        WriteMessage("Hello from client.\r\n");
                        string answer = ReadMessage();
                    }
                    catch (AuthenticationException ex)
                    {
                        ImapSslDisconnect();
                        MessageBox.Show("Authentication failed - closing the connection." + ex.Message);
                    }
                }
            }
    
    private void ImapSslSelect(string foldername)
            {
                if (tcpClient != null && sslStream != null)
                {
                    WriteMessage("STATUS " + foldername + "\r\n");
                    string answer = ReadMessage();
                }
            }
     
    private void ImapSslDisconnect()
            {
                if (tcpClient != null)
                    if (tcpClient.Connected)
                        tcpClient.Close();
            }

    Abschluss:
    Falls jemand eine Idee hat oder sich mit der Streamverbindung und der Kommunikation auskennt, wäre ich über dessen Hilfe sehr erfreut.

    Grüße, Marcus
    Donnerstag, 7. Januar 2010 10:10
  • So ich habe es nun endlich rausgefunden. ;o)

    Für alle die Lösung als C# Code:

    public class ImapObject
        {
            public ImapObject(string _serverName, int _port)
            {
                Connected = false;
    
                dictionary.Fill();
    
                serverName = _serverName;
                port = _port;
            }
    
            System.Net.Sockets.TcpClient tcpClient;
            System.Net.Sockets.NetworkStream nwStream;
            System.Net.Security.SslStream sslStream;
            StreamReader reader;
    
            ImapDictionary dictionary = new ImapDictionary();
    
            public event HaveMessage Have_Message;
    
            private string serverName = string.Empty;
            private int port = 0;
    
            private string userName = string.Empty;
            private string passWord = string.Empty;
    
            public bool Connected { get; set; }
            public bool LoggedIn { get; set; }
    
            public void Run()
            {
                tcpClient = new TcpClient(serverName, port);
    
                if (tcpClient.Connected)
                {
                    CreateStreams();
    
                    string answer = reader.ReadLine();
                    if (answer.Contains(dictionary.MyImap[ImapDictionary.MyType.ResponseOK]))
                    {
                        Connected = true;
                        Have_Message("Connect successfully.");
                    }
                    else
                    {
                        Have_Message("Incorrect credentials.");
                    }
                }
            }
    
            private void CreateStreams()
            {
                nwStream = tcpClient.GetStream();
                sslStream = new SslStream(tcpClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
                sslStream.AuthenticateAsClient(serverName);
                reader = new StreamReader(sslStream);
            }
            private void KillStreams()
            {
                tcpClient = null;
                nwStream = null;
                sslStream = null;
                reader = null;
            }
    
            private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            }
    
            public List<string> ImapCommand(ImapDictionary.MyType typeOfCommand)
            {
                return ImapCommand(typeOfCommand, string.Empty);
            }
            public List<string> ImapCommand(ImapDictionary.MyType typeOfCommand, string command)
            {
                string postData = string.Empty;
                if (command.Length > 0)
                    postData = dictionary.MyImap[typeOfCommand] + " " + command + dictionary.MyImap[ImapDictionary.MyType.CommandEol];
                else
                    postData = dictionary.MyImap[typeOfCommand] + dictionary.MyImap[ImapDictionary.MyType.CommandEol];
    
                try
                {
                    return SendAndReceive(typeOfCommand, postData);
                }
                catch (Exception ex)
                {
                    List<string> errorList = new List<string>();
                    errorList.Add(ex.ToString());
                    return errorList;
                }
            }
    
            private List<string> SendAndReceive(ImapDictionary.MyType typeOfCommand, string _command)
            {
                object locker = new object();
    
                lock (locker)
                {
                    dictionary.CommandVal++;
                    string command = dictionary.CommandIdentifier + _command;
                    byte[] bytes = Encoding.ASCII.GetBytes(command.ToCharArray());
    
                    try
                    {
                        sslStream.Write(bytes, 0, bytes.Length);
    
                        List<string> resultGroup = new List<string>();
    
                        bool dataToReadAvaible = true;
    
                        while (dataToReadAvaible)
                        {
                            string result = reader.ReadLine();
                            resultGroup.Add(result);
    
                            if (result.StartsWith(dictionary.ServerAnswerOk) ||
                                result.StartsWith(dictionary.ServerAnswerNo) ||
                                result.StartsWith(dictionary.ServerAnswerBad))
                            {
                                dataToReadAvaible = false;
                            }
                        }
    
                        return resultGroup;
                    }
                    catch (Exception ex)
                    {
                        List<string> errorList = new List<string>();
                        errorList.Add(ex.ToString());
                        return errorList;
                    }
                }
            }
    
            public delegate void HaveMessage(string message);
        }

    Viel Vergnügen, falls jemand einen IMAP Clienten selbst schreibe möchte. :o)


    Grüße, Marcus
    • Als Antwort markiert NozzNazz Montag, 11. Januar 2010 08:58
    Montag, 11. Januar 2010 08:57
  • Nabend, Also mir stellt sich im Moment das gleich Problem ( Imap MailServer abfrage ) Und ich fand den code als Starthilfe recht hilfreich. Auch wenn einpaar Kommentare schön gewesen wären. *scnr* danke für den Post
    Freitag, 12. November 2010 21:34
  • Hi Marcus,

     

    dein Beitrag gefällt mir sehr gut, leider habe ich ein gewisses Problem mit der Klasse ImapDictionary. Ist dies deine eigene Klasse, oder ist sie Teil des Frameworks?

     

    Viele Grüße

    Waldemar

    Freitag, 26. November 2010 08:46