powered by simpleCommunicator - 2.0.54     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / POP3+SSL м.б. все таки сделать? Какие соображения?
12 сообщений из 12, страница 1 из 1
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960280
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я вот думаю, коль я на .Net проект переписываю, м.б. сразу добавить SSL к POP3.
Какие трудозатраты?
В настоящий момент у меня скачивание писем выполняется сторонней утилитой, вот этой
http://www.interlog.com/~tcharron/getmail.html

Штука на редкость удобная.

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
  Public Sub GetMail(ByVal User As String, ByVal Password As String, ByVal PopServer As String, _
   ByVal ServerPort As String)
    Dim str As String
    str = IO.Path.Combine(Application.StartupPath, "getmail.exe") & _
     " -u " & User & " -pw " & Password & " -s " & PopServer & " -port " & ServerPort & _
     " -delete -dir " & Chr(34) & IO.Path.Combine(path_AppData, "mail") & Chr(34)
    ShellAndContinueNet(str, AppWinStyle.Hide) 'запуск внешней утилиты с ожиданием конца сеанса обмена с POP3 и скачки писем
  End Sub


На выходе имеем MSG1.eml, MSG2.eml в папке path_AppData\mail (стандартный .eml-формат, открываемый в Outlook Express/Почта Windows). Но никакого SSL в помине нет.
Дальнейший разбор принятого через стандартное CDO.Message (это уже другая задача успешно решенная)

Т.е. нужно нечто подогнанное под эту модель (почта скачана/удалена на сервере и MSG1.eml, MSG2.eml в заданной папке) , но с поддержкой SSL.

Как подойти к задаче. Гоглопоиск естественно делал.
Чтоб вот простенькой самодостаточной cmd-утилиты типа той что привел - не нашел.
Навороченные проекты с каким-нибудь питоном и доустановкой кучи всего - не тот путь.
Много говорится о том, что-де любой pop3 клиент можно завернуть в SSL-канал и сделать это можно при помощи OpenSSL, приводится еще слово stunnel, не уверен что мне нужны все эти нагромождения.

Пошерстил по слову .Net + POP3 + SSL

Нашел вот это:
POP3 Email Client (.NET 2.0)
Выглядит вроде привлекательно.
Глянул код.
Что мне понравилось, там в коде упомянается некий SSLStream (штатный .Net -класс?). Подозреваю что это правильный путь. Не?
М.б. этот проект за основу взять?

Или м.б. кто что другое предложите?
Надо написать нечто простенькое, чтоб работало четко и без висяков и непредвиденных ошибок: приконнектился к POP3/SSL, скачал письма если есть (с корректным удалением их на сервере), сохранил письма каждое в свой файл по заданному пути по имени-шаблону, отключился от сервера. Все. Реализовать в виде функции типа той что привел (Public Sub GetMail).
Да, еще. Функция не должна глухо блочить прогу. Моя не блочит, потому что там используется цикл с Application.DoEvents() в ShellAndContinueNet. (как вариант, конечно можно оформить код в отдельный exe как у меня и есть чтоб не морочиться).
Идеология всех этих "потоков" что-то мне не очень нравится, или руку не набил пока. Варианты со всякими Asinc как-то привлекательнее.

В любом случае, не последний вопрос, сколько времени у меня уйдет.
Если допустим за 5-7 дней это сделаю то терпимо.
Если надо месяц мудохаться, то даже не знаю стоит ли счас этим заниматься.
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960442
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Нашел вот это:
POP3 Email Client (.NET 2.0)
Выглядит вроде привлекательно.
Думаю это оптимальный вариант.
Тот случай когда разумно просто перекатать код.
А пока перекатываю с C# на VB.net (не без помощи конвертера, тяжеловат зараза), материал немного усваивается.
Пока что удалось приконнектиться к gmail-у по ssl.

Но код походу зачетный.
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960447
Фотография skyANA
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Дмитрий77Нашел вот это:
POP3 Email Client (.NET 2.0)
Выглядит вроде привлекательно.
Думаю это оптимальный вариант.
Тот случай когда разумно просто перекатать код.
А пока перекатываю с C# на VB.net (не без помощи конвертера, тяжеловат зараза), материал немного усваивается.
Пока что удалось приконнектиться к gmail-у по ssl.

Но код походу зачетный.А зачем перекатывать? Собрать, добавить референс на сборку, создать экземпляр Pop3MailClient.
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960696
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
skyANAА зачем перекатывать? Собрать, добавить референс на сборку, создать экземпляр Pop3MailClient.
Если тупо схавать, то да.
Пока перекатываешь, начинаешь хоть частично понимать что к чему.
И, возможно придется немного переделывать под себя.


Вот эта штука мне заранее внушает недоверие (до ее разбора еще не дошел).
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
    public bool GetRawEmail(int MessageNo, out string EmailText) {
      //send 'RETR int' command to server
      if (!SendRetrCommand(MessageNo)) {
        EmailText = null;
        return false;
      }

      //get the lines
      string response;
      int LineCounter = 0;
      //empty StringBuilder
      if (RawEmailSB==null) {
        RawEmailSB = new StringBuilder(100000);
      } else {
        RawEmailSB.Length = 0;
      }
      isTraceRawEmail = true;
      while (readMultiLine(out response)) {
        LineCounter += 1;
      }
      EmailText = RawEmailSB.ToString();
      TraceFrom("email with {0} lines,  {1} chars received", LineCounter.ToString(), EmailText.Length);
      return true;
    }


1) Во первых что есть StringBuilder( 100000 ), и не пытается ли автор кода искусственно ограничить потенциальный размер письма?
А если там картинка-вложение на несколько мегов? У меня предполагаются именно такие "письма". Несколько мегов конечно круто, но битмап или тифф на 40 страниц теоретически допускается.
2) И так понимаю функция возвращает eml целиком как ByRef String, и вот не уверен я что это есть гуд.
Скорее читаемый стрим надо стримом же сохранять сразу в файл.
Мне надо тупо сохранить eml в файл на диске "как есть" (парсинг сохраненного письма это уже другая задача, ну автор кода правда тоже этим не занимается и слава богу).
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960710
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

Мануал по StringBuilder не пробовал почитать вместо построения гипотез?
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960711
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропил,

ну допустим это capacity, а не максимальный размер.
А че он тогда такую большую берет? Чем стандартная capacity плоха?

Т.е. код грамотный, надо получить EmailText, это будет мыло и его разом save-нуть в файл? И если мыло весит 2 мега то пофиг?
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960724
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А в какой кодировке "RawEmail" сохранять?
US-ASCII ?
Вот так нормально?
Код: vbnet
1.
2.
3.
4.
5.
6.
      'get email
      Dim Email As String = ""
      DemoClient.GetRawEmail(1, Email)
      If Strings.Len(Email) > 0 Then
        Try : IO.File.WriteAllText("C:\ProgramData\MyProga\mail\MSG1.eml", Email, System.Text.Encoding.ASCII) : Catch : End Try
      End If


В "Почта Windows" это чудо, т.е. MSG1.eml на ура открывается.

===
Еще непонятно следующее.
Я пока не дошел до разбора функций (нет их пока у меня в коде)
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
    /// Delete message from server.
    /// The POP3 server marks the message as deleted.  Any future
    /// reference to the message-number associated with the message
    /// in a POP3 command generates an error.  The POP3 server does
    /// not actually delete the message until the POP3 session
    /// enters the UPDATE state.
public bool DeleteEmail(int msg_number)
      if (!executeCommand("DELE " + msg_number.ToString(), out response)) {



Но обратил внимание что после скачивания письма, т.е.
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
    ''' Reads the complete text of a message
    ''' </summary>
    ''' <param name="MessageNo">Email to retrieve</param>
    ''' <param name="EmailText">ASCII string of complete message</param>
    ''' <returns></returns>
    Public Function GetRawEmail(ByVal MessageNo As Integer, ByRef EmailText As String) As Boolean
      'send 'RETR int' command to server
      If Not SendRetrCommand(MessageNo) Then


+ корректное отсоединение от сервера уже имплементировано
письмо с сервера уже удаляется .

Оно конечно логически разумно,
но противоречит "документации" на код.
Как так?
(если это существенно, тестирую пока с gmail.com).

Зависит от сервера и DeleteEmail (в обязательном порядке?)/(для страховки?) нужна (чтоб если что не качать письмо повторно)?
Или она нужна только для удаления письма на сервере без его скачивания ?
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960728
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я так понял, что во всяком случае для gmail.com
1) Для случая GetRawEmail (письмо скачивается) команды DeleteEmail и UndeleteAllEmails бесполезны. Все равно удалится.
2) Команда DeleteEmail может удалить сообщение по выходу (без скачивания), но ее можно до выхода отменить через UndeleteAllEmails

Означает ли это, что если я намерен скачать все мыло и хочу сделать это единожды и наверняка, то я могу ограничиться GetRawEmail не делая DeleteEmail? Или все-таки перестраховаться? пока склоняюсь ко второму варианту т.е.


Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
      'get mailbox statistics
      Dim NumberOfMails As Integer, MailboxSize As Integer
      DemoClient.GetMailboxStats(NumberOfMails, MailboxSize)

      'get emails
      If NumberOfMails > 0 Then
        For i As Integer = 1 To NumberOfMails
          'get email
          Dim Email As String = ""
          DemoClient.GetRawEmail(i, Email)
          If Strings.Len(Email) > 0 Then
            Try : IO.File.WriteAllText("C:\ProgramData\MyProga\mail\MSG" & i.ToString & ".eml", _
             Email, System.Text.Encoding.ASCII) : Catch : End Try
          End If

          'delete email
          DemoClient.DeleteEmail(i) 'оно надо???
        Next
      End If
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960740
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Означает ли это, что если я намерен скачать все мыло и хочу сделать это единожды и наверняка, то я могу ограничиться GetRawEmail не делая DeleteEmail? Или все-таки перестраховаться? пока склоняюсь ко второму варианту т.е.

Проверил с Hotmail. 52 письма мусора выкачал. Без DeleteEmail все осталось на сервере.
Так что однозначно второй вариант ибо зависит от настроек сервера.

Ну, вроде фурычит.
Но она блокирует. В модулях с GUI у меня это не используется, но используется в модулях которые ловят события от COM в реальном времени. Поэтому запуск в лоб как бы нежелателен.
Как с этим быть?
Да, еще. Функция не должна глухо блочить прогу. Моя не блочит, потому что там используется цикл с Application.DoEvents() в ShellAndContinueNet. (как вариант, конечно можно оформить код в отдельный exe как у меня и есть чтоб не морочиться).
Идеология всех этих "потоков" что-то мне не очень нравится, или руку не набил пока.
Отдельным exe-шником оформлять под старую модель?
Мудохаться с потоками и инвоками - ну очень не хочется, глюков больше чем пользы.
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960749
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что значит "мудохаться с потоками"?
Там нет ничего сложного
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38960821
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Честно говоря, не понял вопроса. Нужен SSL для POP3? Обычный TcpClient + SSLStream. Какая кодировка по умолчанию? Во всех доках говорится, что ASCII. Но по факту есть сервера, которые отдают в национальной кодировке.

Исходный код указанной либы не смотрел, но при чтении сообщения автоматом ничего не удаляется. И даже более того, если руками вызвать удаление сообщения, но не вызвать в итоге Close(), то ничего и не удалится.
...
Рейтинг: 0 / 0
POP3+SSL м.б. все таки сделать? Какие соображения?
    #38965861
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На всякий случай выложу сюда допиленный POP3 класс на VB.NET:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
  Public Sub GetMail(ByVal m_PopServer As String, ByVal m_User As String, ByVal m_Password As String, _
   Optional ByVal m_ServerPort As Integer = 110, Optional ByVal m_useSSL As Boolean = False, _
   Optional ByVal m_DeleteEmails As Boolean = True, Optional ByVal m_SaveDir As String = vbNullString, _
   Optional ByVal m_SaveMailPrefix As String = "MSG", Optional ByVal m_SaveMailExt As String = ".eml", _
   Optional ByVal m_TraceFunction As Pop3.TraceHandler = Nothing, Optional ByVal m_TestMode As Boolean = False)

    Try
      ' prepare pop client
      Dim POP3Client As Pop3.cPop3MailClient = _
       New Pop3.cPop3MailClient(m_PopServer, m_ServerPort, m_useSSL, m_User, m_Password)
      POP3Client.IsAutoReconnect = True

      'if tracing needed
      If m_TraceFunction IsNot Nothing Then AddHandler POP3Client.Trace, m_TraceFunction

      POP3Client.ReadTimeout = 60000 'give pop server 60 seconds to answer

      'establish connection
      POP3Client.Connect()

      'get mailbox statistics
      Dim NumberOfMails As Integer, MailboxSize As Integer
      POP3Client.GetMailboxStats(NumberOfMails, MailboxSize)

      If m_TestMode Then
        'get a list of mails
        Dim EmailIds As New List(Of Integer)
        POP3Client.GetEmailIdList(EmailIds)

        'get a list of unique mail ids
        Dim EmailUids As New List(Of Pop3.EmailUid)
        POP3Client.GetUniqueEmailIdList(EmailUids)

        'only show info
        If NumberOfMails > 0 Then
          For i As Integer = 1 To NumberOfMails
            'get email size
            POP3Client.GetEmailSize(i)
          Next
        End If

        'ping server
        POP3Client.NOOP()

      Else

        'get emails
        If NumberOfMails > 0 Then

          If Strings.Len(m_SaveDir) = 0 OrElse IO.Directory.Exists(m_SaveDir) = False Then _
           m_SaveDir = My.Application.Info.DirectoryPath
          If Strings.Len(m_SaveMailPrefix) = 0 Then m_SaveMailPrefix = "MSG"
          If Strings.Len(m_SaveMailExt) = 0 Then m_SaveMailExt = ".eml"
          If Strings.Left(m_SaveMailExt, 1) <> "." Then m_SaveMailExt = "." & m_SaveMailExt

          For i As Integer = 1 To NumberOfMails
            'get email size
            POP3Client.GetEmailSize(i)

            'get email
            Dim Email As String = ""
            POP3Client.GetRawEmail(i, Email)
            If Strings.Len(Email) > 0 Then
              Dim fToSave As String = GetNextEmailFileName(m_SaveDir, m_SaveMailPrefix, m_SaveMailExt)
              Try : IO.File.WriteAllText(fToSave, Email, System.Text.Encoding.ASCII) : Catch : End Try
            End If

            'delete email
            If m_DeleteEmails Then POP3Client.DeleteEmail(i)
          Next
        End If
      End If

      'close connection
      POP3Client.Disconnect()

    Catch ex As Exception
      If m_TraceFunction IsNot Nothing Then
        m_TraceFunction("Run Time Error Occured:")
        m_TraceFunction(ex.Message)
        m_TraceFunction(ex.StackTrace)
      End If
    End Try
 
  End Sub



Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
685.
686.
687.
688.
689.
690.
691.
692.
693.
694.
695.
696.
697.
698.
699.
700.
701.
702.
703.
704.
705.
706.
707.
708.
709.
710.
711.
712.
713.
714.
715.
716.
717.
718.
719.
720.
721.
722.
723.
724.
725.
726.
727.
728.
729.
730.
731.
732.
733.
734.
735.
736.
737.
738.
739.
740.
741.
742.
743.
744.
745.
746.
747.
748.
749.
750.
751.
752.
753.
754.
755.
756.
757.
758.
759.
760.
761.
762.
763.
764.
765.
766.
767.
768.
769.
770.
771.
772.
773.
774.
775.
776.
777.
778.
779.
780.
781.
782.
783.
784.
785.
786.
787.
788.
789.
790.
791.
792.
793.
794.
795.
796.
797.
798.
799.
800.
801.
802.
803.
804.
805.
806.
807.
808.
809.
810.
811.
812.
813.
814.
815.
816.
817.
818.
819.
820.
821.
822.
823.
824.
825.
826.
827.
828.
829.
830.
831.
832.
833.
834.
835.
836.
837.
838.
839.
840.
841.
842.
843.
844.
845.
846.
847.
848.
849.
850.
851.
852.
853.
854.
855.
856.
857.
858.
859.
860.
861.
862.
863.
864.
865.
866.
867.
868.
869.
870.
871.
872.
873.
874.
875.
876.
877.
878.
879.
880.
881.
882.
883.
884.
885.
886.
887.
888.
889.
890.
891.
892.
893.
894.
895.
896.
897.
898.
899.
900.
901.
902.
903.
904.
905.
906.
907.
908.
909.
910.
911.
912.
913.
914.
915.
916.
917.
918.
919.
920.
921.
922.
923.
924.
925.
926.
927.
928.
929.
930.
931.
932.
933.
934.
935.
936.
937.
938.
939.
940.
941.
942.
943.
944.
945.
946.
947.
948.
949.
950.
951.
952.
953.
954.
955.
956.
957.
958.
959.
960.
961.
962.
963.
964.
965.
966.
967.
968.
969.
970.
971.
972.
973.
974.
975.
976.
977.
978.
979.
980.
981.
982.
983.
984.
985.
986.
987.
988.
989.
990.
991.
992.
993.
994.
995.
996.
997.
998.
999.
1000.
1001.
1002.
1003.
1004.
1005.
1006.
1007.
1008.
1009.
Imports System.Net.Sockets
Imports System.Net.Security
Imports System.IO
Imports System.Text

Module ModulePop3

  Public Sub GetMail(ByVal m_PopServer As String, ByVal m_User As String, ByVal m_Password As String, _
   Optional ByVal m_ServerPort As Integer = 110, Optional ByVal m_useSSL As Boolean = False, _
   Optional ByVal m_DeleteEmails As Boolean = True, Optional ByVal m_SaveDir As String = vbNullString, _
   Optional ByVal m_SaveMailPrefix As String = "MSG", Optional ByVal m_SaveMailExt As String = ".eml", _
   Optional ByVal m_TraceFunction As Pop3.TraceHandler = Nothing, Optional ByVal m_TestMode As Boolean = False)

    If m_TraceFunction IsNot Nothing AndAlso m_TestMode = False Then m_TraceFunction("-------------------------")
    Try
      ' prepare pop client
      Dim POP3Client As Pop3.cPop3MailClient = _
       New Pop3.cPop3MailClient(m_PopServer, m_ServerPort, m_useSSL, m_User, m_Password)
      POP3Client.IsAutoReconnect = True

      'if tracing needed
      If m_TraceFunction IsNot Nothing Then AddHandler POP3Client.Trace, m_TraceFunction

      POP3Client.ReadTimeout = 60000 'give pop server 60 seconds to answer

      'establish connection
      POP3Client.Connect()

      'get mailbox statistics
      Dim NumberOfMails As Integer, MailboxSize As Integer
      POP3Client.GetMailboxStats(NumberOfMails, MailboxSize)

      If m_TestMode Then
        'get a list of mails
        Dim EmailIds As New List(Of Integer)
        POP3Client.GetEmailIdList(EmailIds)

        'get a list of unique mail ids
        Dim EmailUids As New List(Of Pop3.EmailUid)
        POP3Client.GetUniqueEmailIdList(EmailUids)

        'only show info
        If NumberOfMails > 0 Then
          For i As Integer = 1 To NumberOfMails
            'get email size
            POP3Client.GetEmailSize(i)
          Next
        End If

        'ping server
        POP3Client.NOOP()

      Else

        'get emails
        If NumberOfMails > 0 Then

          If Strings.Len(m_SaveDir) = 0 OrElse IO.Directory.Exists(m_SaveDir) = False Then _
           m_SaveDir = My.Application.Info.DirectoryPath
          If Strings.Len(m_SaveMailPrefix) = 0 Then m_SaveMailPrefix = "MSG"
          If Strings.Len(m_SaveMailExt) = 0 Then m_SaveMailExt = ".eml"
          If Strings.Left(m_SaveMailExt, 1) <> "." Then m_SaveMailExt = "." & m_SaveMailExt

          For i As Integer = 1 To NumberOfMails
            'get email size
            POP3Client.GetEmailSize(i)

            'get email
            Dim Email As String = ""
            POP3Client.GetRawEmail(i, Email)
            If Strings.Len(Email) > 0 Then
              Dim fToSave As String = GetNextEmailFileName(m_SaveDir, m_SaveMailPrefix, m_SaveMailExt)
              Try : IO.File.WriteAllText(fToSave, Email, System.Text.Encoding.ASCII) : Catch : End Try
            End If

            'delete email
            If m_DeleteEmails Then POP3Client.DeleteEmail(i)
          Next
        End If
      End If

      'close connection
      POP3Client.Disconnect()

    Catch ex As Exception
      If m_TraceFunction IsNot Nothing Then
        m_TraceFunction("Run Time Error Occured:")
        m_TraceFunction(ex.Message)
        m_TraceFunction(ex.StackTrace)
      End If
    End Try
    If m_TraceFunction IsNot Nothing AndAlso m_TestMode = False Then m_TraceFunction("-------------------------")

  End Sub

  Private Function GetNextEmailFileName(ByVal path As String, ByVal pref As String, ByVal ext As String) As String
    Dim tmp_name As String
    Dim i As Integer = 0
    Do
      i = i + 1
      tmp_name = IO.Path.Combine(path, pref & i.ToString & ext)
      If IO.File.Exists(tmp_name) = False Then Return tmp_name
    Loop
  End Function

End Module

Namespace Pop3
  ' Supporting classes and structs
  ' ==============================

  ''' <summary>
  ''' Combines Email ID with Email UID for one email
  ''' The POP3 server assigns to each message a unique Email UID, which will not change for the life time
  ''' of the message and no other message should use the same.
  ''' 
  ''' Exceptions:
  ''' Throws Pop3Exception if there is a serious communication problem with the POP3 server, otherwise
  ''' 
  ''' </summary>
  Public Structure EmailUid
    ''' <summary>
    ''' used in POP3 commands to indicate which message (only valid in the present session)
    ''' </summary>
    Public EmailId As Integer
    ''' <summary>
    ''' Uid is always the same for a message, regardless of session
    ''' </summary>
    Public Uid As String

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="EmailId"></param>
    ''' <param name="Uid"></param>
    Public Sub New(EmailId As Integer, Uid As String)
      Me.EmailId = EmailId
      Me.Uid = Uid
    End Sub
  End Structure

  ''' <summary>
  ''' If anything goes wrong within Pop3MailClient, a Pop3Exception is raised
  ''' </summary>
  Public Class Pop3Exception
    Inherits ApplicationException
    ''' <summary>
    ''' 
    ''' </summary>
    Public Sub New()
    End Sub
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="ErrorMessage"></param>
    Public Sub New(ByVal ErrorMessage As String)
      MyBase.New(ErrorMessage)
    End Sub
  End Class

  ''' <summary>
  ''' A pop 3 connection goes through the following states:
  ''' </summary>
  Public Enum Pop3ConnectionStateEnum
    ''' <summary>
    ''' undefined
    ''' </summary>
    None = 0
    ''' <summary>
    ''' not connected yet to POP3 server
    ''' </summary>
    Disconnected
    ''' <summary>
    ''' TCP connection has been opened and the POP3 server has sent the greeting. POP3 server expects user name and password
    ''' </summary>
    Authorization
    ''' <summary>
    ''' client has identified itself successfully with the POP3, server has locked all messages 
    ''' </summary>
    Connected
    ''' <summary>
    ''' QUIT command was sent, the server has deleted messages marked for deletion and released the resources
    ''' </summary>
    Closed
  End Enum

  ' Delegates for Pop3MailClient
  ' ============================

  ''' <summary>
  ''' If POP3 Server doesn't react as expected or this code has a problem, but
  ''' can continue with the execution, a Warning is called.
  ''' </summary>
  ''' <param name="WarningText"></param>
  ''' <param name="Response">string received from POP3 server</param>
  Public Delegate Sub WarningHandler(ByVal WarningText As String, ByVal Response As String)

  ''' <summary>
  ''' Traces all the information exchanged between POP3 client and POP3 server plus some
  ''' status messages from POP3 client.
  ''' Helpful to investigate any problem.
  ''' Console.WriteLine() can be used
  ''' </summary>
  ''' <param name="TraceText"></param>
  Public Delegate Sub TraceHandler(ByVal TraceText As String)

  ' cPop3MailClient Class
  ' ====================  

  ''' <summary>
  ''' provides access to emails on a POP3 Server
  ''' </summary>
  Public Class cPop3MailClient

    'Events
    '------

    ''' <summary>
    ''' Called whenever POP3 server doesn't react as expected, but no runtime error is thrown.
    ''' </summary>
    Public Event Warning As WarningHandler

    ''' <summary>
    ''' call warning event
    ''' </summary>
    ''' <param name="methodName">name of the method where warning is needed</param>
    ''' <param name="response">answer from POP3 server causing the warning</param>
    ''' <param name="warningText">explanation what went wrong</param>
    ''' <param name="warningParameters"></param>
    Protected Sub CallWarning(ByVal methodName As String, ByVal response As String, _
     ByVal warningText As String, ByVal ParamArray warningParameters As Object())
      warningText = String.Format(warningText, warningParameters)
      RaiseEvent Warning(Convert.ToString(methodName & Convert.ToString(": ")) & warningText, response)
      CallTrace("!! {0}", warningText)
    End Sub

    ''' <summary>
    ''' Shows the communication between PopClient and PopServer, including warnings
    ''' </summary>
    Public Event Trace As TraceHandler

    ''' <summary>
    ''' call Trace event
    ''' </summary>
    ''' <param name="text">string to be traced</param>
    ''' <param name="parameters"></param>
    Protected Sub CallTrace(ByVal text As String, ByVal ParamArray parameters As Object())
      'RaiseEvent Trace(DateTime.Now.ToString("hh:mm:ss ") + m_popServer + " " + String.Format(text, parameters))
      RaiseEvent Trace(DateTime.Now.ToString + Chr(9) + m_popServer + Chr(9) + String.Format(text, parameters))
    End Sub

    ''' <summary>
    ''' Trace information received from POP3 server
    ''' </summary>
    ''' <param name="text">string to be traced</param>
    ''' <param name="parameters"></param>
    Protected Sub TraceFrom(ByVal text As String, ByVal ParamArray parameters As Object())
      CallTrace("   " + String.Format(text, parameters))
    End Sub

    'Properties
    '------

    ''' <summary>
    ''' Get POP3 server name
    ''' </summary>
    Public ReadOnly Property PopServer() As String
      Get
        Return m_popServer
      End Get
    End Property
    ''' <summary>
    ''' POP3 server name
    ''' </summary>
    Protected m_popServer As String

    ''' <summary>
    ''' Get POP3 server port
    ''' </summary>
    Public ReadOnly Property Port() As Integer
      Get
        Return m_port
      End Get
    End Property
    ''' <summary>
    ''' POP3 server port
    ''' </summary>
    Protected m_port As Integer

    ''' <summary>
    ''' Should SSL be used for connection with POP3 server ?
    ''' </summary>
    Public ReadOnly Property UseSSL() As Boolean
      Get
        Return m_useSSL
      End Get
    End Property
    ''' <summary>
    ''' Should SSL be used for connection with POP3 server ?
    ''' </summary>
    Private m_useSSL As Boolean

    ''' <summary>
    ''' should Pop3MailClient automatically reconnect if POP3 server has dropped the 
    ''' connection due to a timeout ?
    ''' </summary>
    Public Property IsAutoReconnect() As Boolean
      Get
        Return m_isAutoReconnect
      End Get
      Set(ByVal value As Boolean)
        m_isAutoReconnect = value
      End Set
    End Property
    Private m_isAutoReconnect As Boolean = False
    'timeout has occured, we try to perform an autoreconnect
    Private isTimeoutReconnect As Boolean = False

    ''' <summary>
    ''' Get / set read timeout (miliseconds)
    ''' </summary>
    Public Property ReadTimeout() As Integer
      Get
        Return m_readTimeout
      End Get
      Set(ByVal value As Integer)
        m_readTimeout = value
        If pop3Stream IsNot Nothing AndAlso pop3Stream.CanTimeout Then
          pop3Stream.ReadTimeout = m_readTimeout
        End If
      End Set
    End Property
    ''' <summary>
    ''' POP3 server read timeout
    ''' </summary>
    Protected m_readTimeout As Integer = -1

    ''' <summary>
    ''' Get owner name of mailbox on POP3 server
    ''' </summary>
    Public ReadOnly Property Username() As String
      Get
        Return m_username
      End Get
    End Property
    ''' <summary>
    ''' Owner name of mailbox on POP3 server
    ''' </summary>
    Protected m_username As String

    ''' <summary>
    ''' Get password for mailbox on POP3 server
    ''' </summary>
    Public ReadOnly Property Password() As String
      Get
        Return m_password
      End Get
    End Property
    ''' <summary>
    ''' Password for mailbox on POP3 server
    ''' </summary>
    Protected m_password As String

    ''' <summary>
    ''' Get connection status with POP3 server
    ''' </summary>
    Public ReadOnly Property Pop3ConnectionState() As Pop3ConnectionStateEnum
      Get
        Return m_pop3ConnectionState
      End Get
    End Property
    ''' <summary>
    ''' connection status with POP3 server
    ''' </summary>
    Protected m_pop3ConnectionState As Pop3ConnectionStateEnum = Pop3ConnectionStateEnum.Disconnected

    ' Methods
    ' -------

    ''' <summary>
    ''' set POP3 connection state
    ''' </summary>
    ''' <param name="State"></param>
    Protected Sub setPop3ConnectionState(ByVal State As Pop3ConnectionStateEnum)
      m_pop3ConnectionState = State
      CallTrace("   Pop3MailClient Connection State {0} reached", State)
    End Sub

    ''' <summary>
    ''' throw exception if POP3 connection is not in the required state
    ''' </summary>
    ''' <param name="requiredState"></param>
    Protected Sub EnsureState(ByVal requiredState As Pop3ConnectionStateEnum)
      If m_pop3ConnectionState <> requiredState Then
        ' wrong connection state
        Throw New Pop3Exception("GetMailboxStats only accepted during connection state: " + requiredState.ToString() + _
         vbLf & " The connection to server " + m_popServer + " is in state " + m_pop3ConnectionState.ToString())
      End If
    End Sub

    'private fields
    '--------------
    ''' <summary>
    ''' TCP to POP3 server
    ''' </summary>
    Private serverTcpConnection As TcpClient
    ''' <summary>
    ''' Stream from POP3 server with or without SSL
    ''' </summary>
    Private pop3Stream As Stream
    ''' <summary>
    ''' Reader for POP3 message
    ''' </summary>
    Protected pop3StreamReader As StreamReader
    ''' <summary>
    ''' char 'array' for carriage return / line feed
    ''' </summary>
    Protected CRLF As String = vbCr & vbLf

    'public methods
    '--------------

    ''' <summary>
    ''' Make POP3 client ready to connect to POP3 server
    ''' </summary>
    ''' <param name="PopServer"><example>pop.gmail.com</example></param>
    ''' <param name="Port"><example>995</example></param>
    ''' <param name="useSSL">True: SSL is used for connection to POP3 server</param>
    ''' <param name="Username"><example>abc@gmail.com<;/example></param>
    ''' <param name="Password">Secret</param>
    Public Sub New(ByVal PopServer As String, ByVal Port As Integer, ByVal useSSL As Boolean, _
     ByVal Username As String, ByVal Password As String)
      Me.m_popServer = PopServer
      Me.m_port = Port
      Me.m_useSSL = useSSL
      Me.m_username = Username
      Me.m_password = Password
    End Sub

    ''' <summary>
    ''' Connect to POP3 server
    ''' </summary>
    Public Sub Connect()
      If (m_pop3ConnectionState <> Pop3ConnectionStateEnum.Disconnected) AndAlso
       (m_pop3ConnectionState <> Pop3ConnectionStateEnum.Closed) AndAlso
       (Not isTimeoutReconnect) Then
        CallWarning("connect", "", "Connect command received, but connection state is: " + m_pop3ConnectionState.ToString())
      Else
        'establish TCP connection
        Try
          CallTrace("   Connect at port {0}", m_port)
          serverTcpConnection = New TcpClient(m_popServer, m_port)
        Catch ex As Exception
          Throw New Pop3Exception("Connection to server " + m_popServer + ", port " + m_port.ToString + " failed." & vbLf & "Runtime Error: " + ex.ToString())
        End Try

        If m_useSSL Then
          'get SSL stream
          Try
            CallTrace("   Get SSL connection")
            pop3Stream = New SslStream(serverTcpConnection.GetStream(), False)
            pop3Stream.ReadTimeout = m_readTimeout
          Catch ex As Exception
            Throw New Pop3Exception("Server " + m_popServer + " found, but cannot get SSL data stream." & vbLf & "Runtime Error: " + ex.ToString())
          End Try

          'perform SSL authentication
          Try
            CallTrace("   Get SSL authentication")
            DirectCast(pop3Stream, SslStream).AuthenticateAsClient(m_popServer)
          Catch ex As Exception
            Throw New Pop3Exception("Server " + m_popServer + " found, but problem with SSL Authentication." & vbLf & "Runtime Error: " + ex.ToString())
          End Try
        Else
          'create a stream to POP3 server without using SSL
          Try
            CallTrace("   Get connection without SSL")
            pop3Stream = serverTcpConnection.GetStream()
            pop3Stream.ReadTimeout = m_readTimeout
          Catch ex As Exception
            Throw New Pop3Exception("Server " + m_popServer + " found, but cannot get data stream (without SSL)." & vbLf & "Runtime Error: " + ex.ToString())
          End Try
        End If

        'get stream for reading from pop server
        'POP3 allows only US-ASCII. The message will be translated in the proper encoding in a later step
        Try
          pop3StreamReader = New StreamReader(pop3Stream, Encoding.ASCII)
        Catch ex As Exception
          If m_useSSL Then
            Throw New Pop3Exception("Server " + m_popServer + " found, but cannot read from SSL stream." & vbLf & "Runtime Error: " + ex.ToString())
          Else
            Throw New Pop3Exception("Server " + m_popServer + " found, but cannot read from stream (without SSL)." & vbLf & "Runtime Error: " + ex.ToString())
          End If
        End Try

        'ready for authorisation
        Dim response As String = ""
        If Not readSingleLine(response) Then
          Throw New Pop3Exception(Convert.ToString("Server " + m_popServer + " not ready to start AUTHORIZATION." & vbLf & "Message: ") & response)
        End If
        setPop3ConnectionState(Pop3ConnectionStateEnum.Authorization)

        'send user name
        If Not executeCommand("USER " + m_username, response) Then
          Throw New Pop3Exception(Convert.ToString("Server " + m_popServer + " doesn't accept username '" + m_username + "'." & vbLf & "Message: ") & response)
        End If

        'send password
        If Not executeCommand("PASS " + m_password, response) Then
          Throw New Pop3Exception(Convert.ToString("Server " + m_popServer + " doesn't accept password '" + m_password + "' for user '" + m_username + "'." & vbLf & "Message: ") & response)
        End If

        setPop3ConnectionState(Pop3ConnectionStateEnum.Connected)
      End If
    End Sub

    ''' <summary>
    ''' Disconnect from POP3 Server
    ''' </summary>
    Public Sub Disconnect()
      If m_pop3ConnectionState = Pop3ConnectionStateEnum.Disconnected OrElse _
       m_pop3ConnectionState = Pop3ConnectionStateEnum.Closed Then
        CallWarning("disconnect", "", "Disconnect received, but was already disconnected.")
      Else
        'ask server to end session and possibly to remove emails marked for deletion
        Try
          Dim response As String = ""
          If executeCommand("QUIT", response) Then
            'server says everything is ok
            setPop3ConnectionState(Pop3ConnectionStateEnum.Closed)
          Else
            'server says there is a problem
            CallWarning("Disconnect", response, Convert.ToString("negative response from server while closing connection: ") & response)
            setPop3ConnectionState(Pop3ConnectionStateEnum.Disconnected)
          End If
        Finally
          'close connection
          If pop3Stream IsNot Nothing Then
            pop3Stream.Close()
          End If

          pop3StreamReader.Close()
        End Try
      End If
    End Sub

    ''' <summary>
    ''' Delete message from server.
    ''' The POP3 server marks the message as deleted.  Any future
    ''' reference to the message-number associated with the message
    ''' in a POP3 command generates an error.  The POP3 server does
    ''' not actually delete the message until the POP3 session
    ''' enters the UPDATE state.
    ''' </summary>
    ''' <param name="msg_number"></param>
    ''' <returns></returns>
    Public Function DeleteEmail(ByVal msg_number As Integer) As Boolean
      EnsureState(Pop3ConnectionStateEnum.Connected)
      Dim response As String = ""
      If Not executeCommand("DELE " + msg_number.ToString(), response) Then
        CallWarning("DeleteEmail", response, "negative response for email (Id: {0}) delete request", msg_number)
        Return False
      End If
      Return True
    End Function

    ''' <summary>
    ''' Get a list of all Email IDs available in mailbox
    ''' </summary>
    ''' <returns></returns>
    Public Function GetEmailIdList(ByRef EmailIds As List(Of Integer)) As Boolean
      EnsureState(Pop3ConnectionStateEnum.Connected)
      EmailIds = New List(Of Integer)()

      'get server response status line
      Dim response As String = ""
      If Not executeCommand("LIST", response) Then
        CallWarning("GetEmailIdList", response, "negative response for email list request")
        Return False
      End If

      'get every email id
      Dim EmailId As Integer
      While readMultiLine(response)
        If Integer.TryParse(response.Split(" "c)(0), EmailId) Then
          EmailIds.Add(EmailId)
        Else
          CallWarning("GetEmailIdList", response, "first characters should be integer (EmailId)")
        End If
      End While
      TraceFrom("{0} email ids received", EmailIds.Count)
      Return True
    End Function

    ''' <summary>
    ''' get size of one particular email
    ''' </summary>
    ''' <param name="msg_number"></param>
    ''' <returns></returns>
    Public Function GetEmailSize(ByVal msg_number As Integer) As Integer
      EnsureState(Pop3ConnectionStateEnum.Connected)
      Dim response As String = ""
      executeCommand("LIST " + msg_number.ToString(), response)
      Dim EmailSize As Integer = 0
      Dim responseSplit As String() = response.Split(" "c)
      If responseSplit.Length < 2 OrElse Not Integer.TryParse(responseSplit(2), EmailSize) Then
        CallWarning("GetEmailSize", response, "'+OK int int' format expected (EmailId, EmailSize)")
      End If

      Return EmailSize
    End Function

    ''' <summary>
    ''' Get a list with the unique IDs of all Email available in mailbox.
    ''' 
    ''' Explanation:
    ''' EmailIds for the same email can change between sessions, whereas the unique Email id
    ''' never changes for an email.
    ''' </summary>
    ''' <param name="EmailIds"></param>
    ''' <returns></returns>
    Public Function GetUniqueEmailIdList(ByRef EmailIds As List(Of EmailUid)) As Boolean
      EnsureState(Pop3ConnectionStateEnum.Connected)
      EmailIds = New List(Of EmailUid)()

      'get server response status line
      Dim response As String = ""
      If Not executeCommand("UIDL ", response) Then
        CallWarning("GetUniqueEmailIdList", response, "negative response for email list request")
        Return False
      End If

      'get every email unique id
      Dim EmailId As Integer
      While readMultiLine(response)
        Dim responseSplit As String() = response.Split(" "c)
        If responseSplit.Length < 2 Then
          CallWarning("GetUniqueEmailIdList", response, "response not in format 'int string'")
        ElseIf Not Integer.TryParse(responseSplit(0), EmailId) Then
          CallWarning("GetUniqueEmailIdList", response, "first charaters should be integer (Unique EmailId)")
        Else
          EmailIds.Add(New EmailUid(EmailId, responseSplit(1)))
        End If
      End While
      TraceFrom("{0} unique email ids received", EmailIds.Count)
      Return True
    End Function

    ''' <summary>
    ''' get a list with all currently available messages and the UIDs
    ''' </summary>
    ''' <param name="EmailIds">EmailId Uid list</param>
    ''' <returns>false: server sent negative response (didn't send list)</returns>
    Public Function GetUniqueEmailIdList(ByRef EmailIds As SortedList(Of String, Integer)) As Boolean
      EnsureState(Pop3ConnectionStateEnum.Connected)
      EmailIds = New SortedList(Of String, Integer)()

      'get server response status line
      Dim response As String = ""
      If Not executeCommand("UIDL", response) Then
        CallWarning("GetUniqueEmailIdList", response, "negative response for email list request")
        Return False
      End If

      'get every email unique id
      Dim EmailId As Integer
      While readMultiLine(response)
        Dim responseSplit As String() = response.Split(" "c)
        If responseSplit.Length < 2 Then
          CallWarning("GetUniqueEmailIdList", response, "response not in format 'int string'")
        ElseIf Not Integer.TryParse(responseSplit(0), EmailId) Then
          CallWarning("GetUniqueEmailIdList", response, "first charaters should be integer (Unique EmailId)")
        Else
          EmailIds.Add(responseSplit(1), EmailId)
        End If
      End While
      TraceFrom("{0} unique email ids received", EmailIds.Count)
      Return True
    End Function

    ''' <summary>
    ''' get size of one particular email
    ''' </summary>
    ''' <param name="msg_number"></param>
    ''' <returns></returns>
    Public Function GetUniqueEmailId(ByVal msg_number As EmailUid) As Integer
      EnsureState(Pop3ConnectionStateEnum.Connected)
      Dim response As String = ""
      executeCommand("LIST " + msg_number.ToString(), response)
      Dim EmailSize As Integer = 0
      Dim responseSplit As String() = response.Split(" "c)
      If responseSplit.Length < 2 OrElse Not Integer.TryParse(responseSplit(2), EmailSize) Then
        CallWarning("GetEmailSize", response, "'+OK int int' format expected (EmailId, EmailSize)")
      End If

      Return EmailSize
    End Function

    ''' <summary>
    ''' Sends an 'empty' command to the POP3 server. Server has to respond with +OK
    ''' </summary>
    ''' <returns>true: server responds as expected</returns>
    Public Function NOOP() As Boolean
      EnsureState(Pop3ConnectionStateEnum.Connected)
      Dim response As String = ""
      If Not executeCommand("NOOP", response) Then
        CallWarning("NOOP", response, "negative response for NOOP request")
        Return False
      End If
      Return True
    End Function

    ''' <summary>
    ''' Should the raw content, the US-ASCII code as received, be traced
    ''' GetRawEmail will switch it on when it starts and off once finished
    ''' 
    ''' Inheritors might use it to get the raw email
    ''' </summary>
    Protected isTraceRawEmail As Boolean = False


    ''' <summary>
    ''' contains one MIME part of the email in US-ASCII, needs to be translated in .NET string (Unicode)
    ''' contains the complete email in US-ASCII, needs to be translated in .NET string (Unicode)
    ''' For speed reasons, reuse StringBuilder
    ''' </summary>
    Protected RawEmailSB As StringBuilder

    ''' <summary>
    ''' Reads the complete text of a message
    ''' </summary>
    ''' <param name="MessageNo">Email to retrieve</param>
    ''' <param name="EmailText">ASCII string of complete message</param>
    ''' <returns></returns>
    Public Function GetRawEmail(ByVal MessageNo As Integer, ByRef EmailText As String) As Boolean
      'send 'RETR int' command to server
      If Not SendRetrCommand(MessageNo) Then
        EmailText = Nothing
        Return False
      End If

      'get the lines
      Dim response As String = ""
      Dim LineCounter As Integer = 0
      'empty StringBuilder
      If RawEmailSB Is Nothing Then
        RawEmailSB = New StringBuilder(100000)
      Else
        RawEmailSB.Length = 0
      End If
      isTraceRawEmail = True
      While readMultiLine(response)
        LineCounter += 1
      End While
      EmailText = RawEmailSB.ToString()
      TraceFrom("email with {0} lines,  {1} chars received", LineCounter.ToString(), EmailText.Length)
      Return True
    End Function

    ' ''' <summary>
    ' ''' Requests from POP3 server a specific email and returns a stream with the message content (header and body)
    ' ''' </summary>
    ' ''' <param name="MessageNo"></param>
    ' ''' <param name="EmailStreamReader"></param>
    ' ''' <returns>false: POP3 server cannot provide this message</returns>
    'Public Function GetEmailStream(ByVal MessageNo As Integer, ByRef EmailStreamReader As StreamReader) As Boolean
    '  'send 'RETR int' command to server
    '  If Not SendRetrCommand(MessageNo) Then
    '    EmailStreamReader = Nothing
    '    Return False
    '  End If
    '  EmailStreamReader = sslStreamReader
    '  Return True
    'End Function

    ''' <summary>
    ''' Unmark any emails from deletion. The server only deletes email really
    ''' once the connection is properly closed.
    ''' </summary>
    ''' <returns>true: emails are unmarked from deletion</returns>
    Public Function UndeleteAllEmails() As Boolean
      EnsureState(Pop3ConnectionStateEnum.Connected)
      Dim response As String = ""
      Return executeCommand("RSET", response)
    End Function

    ''' <summary>
    ''' Get mailbox statistics
    ''' </summary>
    ''' <param name="NumberOfMails"></param>
    ''' <param name="MailboxSize"></param>
    ''' <returns></returns>
    Public Function GetMailboxStats(ByRef NumberOfMails As Integer, ByRef MailboxSize As Integer) As Boolean
      EnsureState(Pop3ConnectionStateEnum.Connected)

      'interpret response
      Dim response As String = ""
      NumberOfMails = 0
      MailboxSize = 0
      If executeCommand("STAT", response) Then
        'got a positive response
        Dim responseParts As String() = response.Split(" "c)
        If responseParts.Length < 2 Then
          'response format wrong
          Throw New Pop3Exception(Convert.ToString("Server " + m_popServer + " sends illegally formatted response." + _
           vbLf & "Expected format: +OK int int" + _
           vbLf & "Received response: ") & response)
        End If
        NumberOfMails = Integer.Parse(responseParts(1))
        MailboxSize = Integer.Parse(responseParts(2))
        Return True
      End If
      Return False
    End Function

    ''' <summary>
    ''' Send RETR command to POP 3 server to fetch one particular message
    ''' </summary>
    ''' <param name="MessageNo">ID of message required</param>
    ''' <returns>false: negative server respond, message not delivered</returns>
    Protected Function SendRetrCommand(ByVal MessageNo As Integer) As Boolean
      EnsureState(Pop3ConnectionStateEnum.Connected)
      ' retrieve mail with message number
      Dim response As String = ""
      If Not executeCommand("RETR " + MessageNo.ToString(), response) Then
        CallWarning("GetRawEmail", response, "negative response for email (ID: {0}) request", MessageNo)
        Return False
      End If
      Return True
    End Function

    'Helper methodes
    '---------------

    Public isDebug As Boolean = False

    ''' <summary>
    ''' sends the 4 letter command to POP3 server (adds CRLF) and waits for the
    ''' response of the server
    ''' </summary>
    ''' <param name="command">command to be sent to server</param>
    ''' <param name="response">answer from server</param>
    ''' <returns>false: server sent negative acknowledge, i.e. server could not execute command</returns>
    Private Function executeCommand(ByVal command As String, ByRef response As String) As Boolean
      'send command to server
      Dim commandBytes As Byte() = System.Text.Encoding.ASCII.GetBytes((command & CRLF).ToCharArray())
      CallTrace("Tx '{0}'", command)
      Dim isSupressThrow As Boolean = False
      Try
        pop3Stream.Write(commandBytes, 0, commandBytes.Length)
        If isDebug Then
          isDebug = False
          Throw New IOException("Test", New SocketException(10053))
        End If
      Catch ex As IOException
        'Unable to write data to the transport connection. Check if reconnection should be tried
        isSupressThrow = executeReconnect(ex, command, commandBytes)
        If Not isSupressThrow Then
          Throw
        End If
      End Try
      pop3Stream.Flush()

      'read response from server
      response = Nothing
      Try
        response = pop3StreamReader.ReadLine()
      Catch ex As IOException
        'Unable to write data to the transport connection. Check if reconnection should be tried
        isSupressThrow = executeReconnect(ex, command, commandBytes)
        If isSupressThrow Then
          'wait for response one more time
          response = pop3StreamReader.ReadLine()
        Else
          Throw
        End If
      End Try
      If response Is Nothing Then
        Throw New Pop3Exception("Server " + m_popServer + " has not responded, timeout has occured.")
      End If
      CallTrace("Rx '{0}'", response)
      Return (response.Length > 0 AndAlso response(0) = "+"c)
    End Function

    ''' <summary>
    ''' reconnect, if there is a timeout exception and isAutoReconnect is true
    ''' 
    ''' </summary>
    Private Function executeReconnect(ByVal ex As IOException, ByVal command As String, _
     ByVal commandBytes As Byte()) As Boolean
      If ex.InnerException IsNot Nothing AndAlso TypeOf ex.InnerException Is SocketException Then
        'SocketException
        Dim innerEx As SocketException = DirectCast(ex.InnerException, SocketException)
        If innerEx.ErrorCode = 10053 Then
          'probably timeout: An established connection was aborted by the software in your host machine.
          CallWarning("ExecuteCommand", "", "probably timeout occured")
          If m_isAutoReconnect Then
            'try to reconnect and send one more time
            isTimeoutReconnect = True
            Try
              CallTrace("   try to auto reconnect")
              Connect()

              CallTrace("   reconnect successful, try to resend command")
              CallTrace("Tx '{0}'", command)
              pop3Stream.Write(commandBytes, 0, commandBytes.Length)
              pop3Stream.Flush()
              Return True
            Finally
              isTimeoutReconnect = False
            End Try

          End If
        End If
      End If
      Return False
    End Function

    ' ''' <summary>
    ' ''' sends the 4 letter command to POP3 server (adds CRLF)
    ' ''' </summary>
    ' ''' <param name="command"></param>
    'Protected Sub SendCommand(ByVal command As String)
    '  Dim commandBytes As Byte() = System.Text.Encoding.ASCII.GetBytes((command & CRLF).ToCharArray())
    '  CallTrace("Tx '{0}'", command)
    '  Try
    '    pop3Stream.Write(commandBytes, 0, commandBytes.Length)
    '  Catch ex As IOException
    '    'Unable to write data to the transport connection:
    '    If ex.InnerException IsNot Nothing AndAlso TypeOf ex.InnerException Is SocketException Then
    '      'SocketException
    '      Dim innerEx As SocketException = DirectCast(ex.InnerException, SocketException)
    '      If innerEx.ErrorCode = 10053 Then
    '        'probably timeout: An established connection was aborted by the software in your host machine.
    '        CallWarning("SendCommand", "", "probably timeout occured")
    '        If m_isAutoReconnect Then
    '          'try to reconnect and send one more time
    '          isTimeoutReconnect = True
    '          Try
    '            CallTrace("   try to auto reconnect")
    '            Connect()

    '            CallTrace("   reconnect successful, try to resend command")
    '            CallTrace("Tx '{0}'", command)
    '            pop3Stream.Write(commandBytes, 0, commandBytes.Length)
    '          Finally
    '            isTimeoutReconnect = False
    '          End Try
    '          Return
    '        End If
    '      End If
    '    End If
    '    Throw
    '  End Try
    '  pop3Stream.Flush()
    'End Sub

    ''' <summary>
    ''' read single line response from POP3 server. 
    ''' <example>Example server response: +OK asdfkjahsf</example>
    ''' </summary>
    ''' <param name="response">response from POP3 server</param>
    ''' <returns>true: positive response</returns>
    Protected Function readSingleLine(ByRef response As String) As Boolean
      response = Nothing
      Try
        response = pop3StreamReader.ReadLine()
      Catch ex As Exception
        Dim s As String = ex.Message
      End Try
      If response Is Nothing Then
        Throw New Pop3Exception("Server " + m_popServer + " has not responded, timeout has occured.")
      End If
      CallTrace("Rx '{0}'", response)
      Return (response.Length > 0 AndAlso response(0) = "+"c)
    End Function

    ''' <summary>
    ''' read one line in multiline mode from the POP3 server. 
    ''' </summary>
    ''' <param name="response">line received</param>
    ''' <returns>false: end of message</returns>
    Protected Function readMultiLine(ByRef response As String) As Boolean
      response = Nothing
      response = pop3StreamReader.ReadLine()
      If response Is Nothing Then
        Throw New Pop3Exception("Server " + m_popServer + " has not responded, probably timeout has occured.")
      End If
      If isTraceRawEmail Then
        'collect all responses as received
        RawEmailSB.Append(response & CRLF)
      End If
      'check for byte stuffing, i.e. if a line starts with a '.', another '.' is added, unless
      'it is the last line
      If response.Length > 0 AndAlso response(0) = "."c Then
        If response = "." Then
          'closing line found
          Return False
        End If
        'remove the first '.'
        response = response.Substring(1, response.Length - 1)
      End If
      Return True
    End Function

  End Class

End Namespace

...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / POP3+SSL м.б. все таки сделать? Какие соображения?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]