На всякий случай выложу сюда допиленный POP3 класс на VB.NET:
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
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
|