На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: maxim84_, juice
  
> Реализация протокола POP3
    POP3 (Post Office Protocol version 3 - протокол приёма почты) нужен для приёма почты с почтового сервера. Использует 110
    порт, по которому посылаются команды и текст письма. На написание этой статьи меня сподвигло то что после долгих поисков
    в сети примера, показывающего как работать с POP3 протоколом с помощью VB.NET так и не привело к успеху, но благодаря
    FlyDead'у, который поделился примером на С# (с хорошими коментариями) мне всетаки удалость приконектиться к 110 порту
    своего почтового сервера и забрать оттудого свою почту. Далее я приведу код любезно предоставленный FlyDead'ом и подробно
    опишу код на VB.NET

    ExpandedWrap disabled
      Public void CheckMail()
      {
      NetworkStream ns;
                  StreamReader sr;  //два потока для чтения из потока
                  StreamWriter sw;  //и для записи в поток
                  String response; //для хранения результата запроса
                  
                  TcpClient tcpClient = new TcpClient(); //создаем клиент
                  try
                  {
                      tcpClient.Connect(cConfig.ServerPop,Convert.ToInt32(cConfig.PortPop));
                  }
                  catch(SocketException sExc)
                  {
                      MessageBox.Show("Соединение неустановлено \n"+"Проверьте настройки POP3 сервера и номер порта \n"+sExc.Message);
                      Return;
                  }
                  catch(Exception eX)
                  {
                      MessageBox.Show("Соединение неустановлено \n"+eX.Message);
                      Return;
                  }
                  ns = tcpClient.GetStream(); //запускаем потоки
                  sr = new StreamReader(ns);
                  sw = new StreamWriter(ns);
                  
                  response = sr.ReadLine();
                  sw.WriteLine("User " + cConfig.UserPop); //посылаем юзера
                  sw.Flush();  
                  response = sr.ReadLine(); //опять читаем что вернул сервер
                  
                  If (response.Substring(0,3) == "-ER") //если вернул сообщение об ошибке
                  {
                      MessageBox.Show("Неверный логин","Ошибка аутентификации",MessageBoxButtons.OK,MessageBoxIcon.Error);
                      Return;
                  }
                  sw.WriteLine("Pass " + cConfig.PasswordPop); //Послылаем пароль
                  sw.Flush(); //очистка
       
                  response = sr.ReadLine(); //опять читаем
                  If (response.Substring(0,4) == "-ERR") //если не ошибка то идем дальше
                  {
                      MessageBox.Show("Неверный пароль","Ошибка аутентификации",MessageBoxButtons.OK,MessageBoxIcon.Error);
                      Return;
                  }
                  sw.WriteLine("stat");
                  sw.Flush();
                  response = sr.ReadLine();
                  String[] nummess = response.Split(' ');
                  Int totmessages;
                  totmessages = Convert.ToInt16(nummess[1]);
                  If (totmessages > 0)
                  {
                      notifyIcon1.Icon = (System.Drawing.Icon)resources.GetObject("2.ico");
                      MessageBox.Show(Convert.ToString(totmessages)+" новых сообщений");
                  }
                  Else
                  {
                      notifyIcon1.Icon = (System.Drawing.Icon)resources.GetObject("1.ico");
                  }
                  tcpClient.Close();
              }





    А теперь все то же самое на VB.NET
    1. Шаг первый, надо соединиться с сервером, вот код который это делает:

    ExpandedWrap disabled
      Dim client As Net.Sockets.TcpClient
          Dim sr As IO.StreamReader
          Dim sw As IO.StreamWriter
          Dim ns As Net.Sockets.NetworkStream
          Dim otvet As String
          'соединяемся с сервером
              client = New Net.Sockets.TcpClient
              Try
                  client.Connect(server, 110)
              Catch e As Exception
                  MessageBox.Show("Соединение не установленно" + e.ToString, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, False)
                  Return
              End Try
              ns = client.GetStream
              sr = New IO.StreamReader(ns, Encoding.ASCII, True) 'это то что отправляет наши команды на сервер
              sw = New IO.StreamWriter(ns)                       'а это то что читает ответы сервера
              otvet = sr.ReadLine()                              'это наш ответ от сервера


    На это нам сервер должен ответить +ОК [какойто текст]. В конце каждой отправленной сервером строки
    обязательно символы перехода на новую строку(chr(13) & chr(10))


    2.Второй шаг, после утвердительного ответа сервера отправляем имя пользователя

    user [имя] & chr(13) & chr(10)

    На что сервер нам может ответить следующее:

    +OK [какойто текст]
    - такой пользователь существует, продолжайте
    -ERR [какойто текст] - ошибка, либо такого пользователя нет

    Вот код который это делает:


    ExpandedWrap disabled
              sw.WriteLine("User " & user & Chr(13) & Chr(10))
              sw.Flush()
              otvet = sr.ReadLine()
              If otvet.Substring(0, 3) = "-ER" Then _
             MessageBox.Show("Неверный логин", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error,_
      MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, False)



    3.Далее посылаем серверу пароль

    pass [****] & chr(13) & chr(10) Вместо **** указывается пароль.

    На что сервер нам опять ответит следующим:
    +OK [какойто текст] - пароль верный, продолжайте
    -ERR [какойто текст] - ошибка, либо неверный пароль

    Вот код который это делает:

    ExpandedWrap disabled
               'отправляем пароль
              sw.WriteLine("Pass " & pass & Chr(13) & Chr(10))
              sw.Flush()
              otvet = sr.ReadLine
              If otvet.Substring(0, 4) = "-ER" Then _
             MessageBox.Show("Неверный пароль", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error,_
      MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, False)



    4.Теперь можно определить количество новых писем на сервере, и их общий объём, для этого отправим
    stat

    Ответом будет
    +OK [кол-во] [объем]

    ExpandedWrap disabled
          Dim nummess As Array
          Dim totmessages As Integer
              sw.WriteLine("stat")
              sw.Flush()
              otvet = sr.ReadLine()
              nummess = otvet.Split(" ")
              totmessages = CInt(nummess(1))



    5.Для того чтобы определить индексы писем и объем каждого по отдельности, отправляем
    list

    Сервер ответит списком с номером и объемом письма
    +OK 2 messages 320
    1 120
    2 200
    .

    Список оканчивается переходом на новую строку и знаком "."


    ExpandedWrap disabled
          Dim i As Integer
          Dim MessageArr() As String
              'получаем идеинтификаторы писем
              sw.WriteLine("list")
              sw.Flush()
              otvet = sr.ReadLine()
              Debug.Print(otvet)
              myArr = otvet.Split(" ")
              ReDim MessageArr(totmessages - 1)
              For i = 0 To CInt(myArr(1)) - 1
                  MessageArr(i) = (sr.ReadLine())
              Next



    6.Теперь мы можем производить разные операции с письмами
    dele [x]
    Удаление сообщения номер x. Изменения вступают в силу только после корректного
    закрытия соединения.

    ExpandedWrap disabled
              sw.WriteLine("dele x") 'х это идеинтификатор письма
              sw.Flush()
              otvet = sr.ReadLine()



    Возможные ответы:
    +OK [какойто текст] - письмо удалено
    -ERR [какойто текст] - нет письма с таким идеинтификатором

    retr [x]
    Приём сообщения номер x. Оно оканчивается переходом на новую строку и знаком "."

    ExpandedWrap disabled
              'получаем письма
              Dim x As Integer = 0
              sr = New IO.StreamReader(ns, Encoding.Default, True) 'Encoding.Default вот чего не хватало для чтения руских букв
              For i = 0 To (totmessages - 1)
                  sw.WriteLine("retr " & (i + 1))
                  sw.Flush()
                  FileOpen(1, Application.StartupPath & "\mails\Mail" & MessageArr(i) & ".txt", OpenMode.Append, OpenAccess.Write)
                  Do While otvet <> "."
                      otvet = sr.ReadLine
                      Debug.Print(otvet)
                      Print(1, otvet & vbNewLine)
                  Loop
                  FileClose(1)
              Next i


    Возможные ответы:
    +OK [какойто текст] - вот ваше письмо
    -ERR [какойто текст] - нет такого письма

    Примеры:

    +OK 120 octets
    [заголовок письма]
    [текст письма]
    .




    Дополнительные POP3 команды

    Следующие дополнительные команды дают вам большую свободу при работе с
    сообщениями:

    Команда: TOP [сообщение] [n]

    Аргументы: [сообщение] - номер сообщения [n] - положительное число
    (обязательный аргумент)

    Описание: Если ответ сервера положительный, то после него он передаёт
    заголовки сообщения и указанное кол - во строк из тела сообщения.

    Возможные ответы:

    +OK top of message follows
    -ERR no such message

    Примеры:

    C: TOP 1 10 S: +OK
    S: <здесь POP3 сервер передаёт заголовки
    первого сообщения и первые 10-ть строк из тела сообщения.>
    S: . ...
    C: TOP 100 3
    S: -ERR no such message


    Команда: UIDL [сообщение]
    Аргументы: [сообщение] - номер сообщения (необязательный аргумент).

    Описание: Если был указан номер сообщения, то сервер выдаёт уникальный
    идентификатор для этого сообщения. Если аргумент не был передан, то
    идентификаторы перечисляются для всех сообщений, кроме помеченных для
    удаления.

    Возможные ответы:
    +OK unique-id listing follows
    -ERR no such message


    Примеры:

    C: UIDL S: +OK
    S: 1 whqtswO00WBw418f9t5JxYwZ
    S: 2 QhdPYR:00WBw1Ph7x7
    S: . ...
    C: UIDL 2
    S: +OK 2 QhdPYR:00WBw1Ph7x7 ...
    C: UIDL 3
    S: -ERR no such message, only 2 messages in maildrop



    Команда:loop
    Эта команда просто говорит серверу, что мы ещё висим на порту, чтобы он не закрывал соединение
    после длительной паузы.

    Команда:quit
    Закрытие соединения.

    Эта тема была разделена из темы "Наполнение и развитие FAQ"
    Прикреплённый файлПрикреплённый файлbasPOP3.rar (1.15 Кбайт, скачиваний: 463)
    Истина где-то рядом!?!
      Цитата Pit-Bul @
      3.Далее посылаем серверу пароль

      pass [****] & chr(13) & chr(10) Вместо **** указывается пароль.

      На что сервер нам опять ответит следующим:
      +OK [какойто текст] - пароль верный, продолжайте
      -ERR [какойто текст] - ошибка, либо неверный пароль

      Вот код который это делает:

      ExpandedWrap disabled
                 'отправляем пароль
                sw.WriteLine("Pass " & pass & Chr(13) & Chr(10))
                sw.Flush()
                otvet = sr.ReadLine
                If otvet.Substring(0, 4) = "-ER" Then _
               MessageBox.Show("Неверный пароль", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error,_
        MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, False)

      Сегодьня такой способ проверки пароля на сервере pop.mail.ru не работает. Выдаёт ошибку, что пароль неверный, а в переменной "otvet" текст такой: -ERR Unknown command:"". Жаль.
        zipa455, возможно сервер использует какой либо шифрованный метод аутеинтификации
        Истина где-то рядом!?!
          ExpandedWrap disabled
                    If otvet.Substring(0, 4) = "-ER"

          В любом случае вернёт false. Независимо от того что будет в переменной otvet.
          Правильно будет либо так:
          ExpandedWrap disabled
                    If otvet.Substring(0, 3) = "-ER"

          либо так:
          ExpandedWrap disabled
                    If otvet.Substring(0, 4) = "-ERR"


          Кстати такой код отлично работает. Проверяно только что.
          ExpandedWrap disabled
                    private void button2_Click(object sender, EventArgs e)
                    {
                        NetworkStream ns;
                        StreamReader rs;
                        StreamWriter ws;
                        String response;
                        String userName = "user@mail.ru";
                        String pass = "password";
             
                        TcpClient client = new TcpClient();
                        try
                        {
                            client.Connect("pop.mail.ru", (Int32)110);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("Соединение не установлено! \n" + ex.Message, "Ошибка соединения!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        ns = client.GetStream();
                        rs = new StreamReader(ns);
                        ws = new StreamWriter(ns);
                        response = rs.ReadLine();
                        ws.WriteLine("User " + userName);
                        ws.Flush();
                        response = rs.ReadLine();
                        if (response.Substring(0, 3) == "-ER")
                        {
                            MessageBox.Show("Неверный логин", "Ошибка аутентификации", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            client.Close();
                            return;
                        }
                        ws.WriteLine("Pass " + pass);
                        ws.Flush();
                        response = rs.ReadLine();
                        if (response.Substring(0, 3) == "-ER")
                        {
                            MessageBox.Show("Неверный пароль", "Ошибка аутентификации", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            client.Close();
                            return;
                        }
                        MessageBox.Show("Соединение установлено!");
                        client.Close();
                    }
          Сообщение отредактировано: SmartX -
            Ребята, вот такой вопрос: Как автоматически определить настройки почтового сервера?
            Пример: в Outlook вводим только логин, пароль, почтовый адрес и все. А Outlook сам автоматом определяет pop3.domain и порт.
            Определяет даже не стандартные порты и необходимость использования SSL.
              коллеги с pop.gmail.com и порт=995 не работает, никто с gmail не сделал?
              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
              0 пользователей:


              Рейтинг@Mail.ru
              [ Script Execution time: 0,1261 ]   [ 17 queries used ]   [ Generated: 23.09.17, 20:17 GMT ]