Hello there and thanks so much for an excellent class, it really set me on the right path for a bulk mailer i'm writing (dont worry its not spam!!).
Only hassle was bounce removal, for this i only needer the headers so i've added another function "GetEmailHeader".
Maybe a ne release with this functionality would be a good idea. Added the code but anyone wants to email then please ask me. stephen.adam@gmail.com
<br />
<br />
using System;<br />
using System.Collections.Generic;<br />
using System.IO;<br />
using System.Net;<br />
using System.Net.Sockets;<br />
using System.Net.Security;<br />
using System.Text;<br />
<br />
namespace DiscoveryMassMailer.Resources{<br />
<br />
namespace Pop3 {<br />
<br />
public struct EmailUid {<br />
public int EmailId;<br />
public string Uid;<br />
<br />
public EmailUid(int EmailId, string Uid) {<br />
this.EmailId = EmailId;<br />
this.Uid = Uid;<br />
}<br />
}<br />
<br />
<br />
public class Pop3Exception:ApplicationException {<br />
public Pop3Exception() { }<br />
public Pop3Exception(string ErrorMessage) : base(ErrorMessage) { }<br />
}<br />
<br />
<br />
public enum Pop3ConnectionStateEnum {<br />
None=0,<br />
Disconnected,<br />
Authorization,<br />
Connected,<br />
Closed<br />
}<br />
<br />
<br />
<br />
public delegate void WarningHandler(string WarningText, string Response);<br />
<br />
<br />
public delegate void TraceHandler(string TraceText);<br />
<br />
<br />
<br />
public class Pop3MailClient {<br />
<br />
<br />
public event WarningHandler Warning;<br />
<br />
protected void CallWarning(string methodName, string response, string warningText, params object[] warningParameters) {<br />
warningText = string.Format(warningText, warningParameters);<br />
if (Warning!=null) {<br />
Warning(methodName + ": " + warningText, response);<br />
}<br />
CallTrace("!! {0}", warningText);<br />
}<br />
<br />
<br />
public event TraceHandler Trace;<br />
<br />
protected void CallTrace(string text, params object[] parameters) {<br />
if (Trace!=null) {<br />
Trace(DateTime.Now.ToString("hh:mm:ss ") + popServer + " " + string.Format(text, parameters));<br />
}<br />
}<br />
<br />
protected void TraceFrom(string text, params object[] parameters) {<br />
if (Trace!=null) {<br />
CallTrace(" " + string.Format(text, parameters));<br />
}<br />
}<br />
<br />
<br />
<br />
public string PopServer {<br />
get { return popServer; }<br />
}<br />
protected string popServer;<br />
<br />
<br />
public int Port {<br />
get { return port; }<br />
}<br />
protected int port;<br />
<br />
<br />
public bool UseSSL {<br />
get { return useSSL; }<br />
}<br />
private bool useSSL;<br />
<br />
<br />
public bool IsAutoReconnect {<br />
get { return isAutoReconnect; }<br />
set { isAutoReconnect = value; }<br />
}<br />
private bool isAutoReconnect = false;<br />
private bool isTimeoutReconnect = false;<br />
<br />
<br />
<br />
public int ReadTimeout {<br />
get { return readTimeout; }<br />
set {<br />
readTimeout = value;<br />
if (pop3Stream!=null && pop3Stream.CanTimeout) {<br />
pop3Stream.ReadTimeout = readTimeout;<br />
}<br />
}<br />
}<br />
protected int readTimeout = -1;<br />
<br />
<br />
public string Username {<br />
get { return username; }<br />
}<br />
protected string username;<br />
<br />
<br />
public string Password {<br />
get { return password; }<br />
}<br />
protected string password;<br />
<br />
<br />
public Pop3ConnectionStateEnum Pop3ConnectionState {<br />
get { return pop3ConnectionState; }<br />
}<br />
protected Pop3ConnectionStateEnum pop3ConnectionState = Pop3ConnectionStateEnum.Disconnected;<br />
<br />
<br />
<br />
protected void setPop3ConnectionState(Pop3ConnectionStateEnum State) {<br />
pop3ConnectionState = State;<br />
CallTrace(" Pop3MailClient Connection State {0} reached", State);<br />
}<br />
<br />
protected void EnsureState(Pop3ConnectionStateEnum requiredState) {<br />
if (pop3ConnectionState!=requiredState) {<br />
throw new Pop3Exception("GetMailboxStats only accepted during connection state: " + requiredState.ToString() + <br />
"\n The connection to server "+ popServer + " is in state " + pop3ConnectionState.ToString());<br />
}<br />
}<br />
<br />
<br />
private TcpClient serverTcpConnection;<br />
private Stream pop3Stream;<br />
protected StreamReader pop3StreamReader;<br />
protected string CRLF = "\r\n";<br />
<br />
<br />
<br />
public Pop3MailClient(string PopServer, int Port, bool useSSL, string Username, string Password) {<br />
this.popServer = PopServer;<br />
this.port = Port;<br />
this.useSSL = useSSL;<br />
this.username = Username;<br />
this.password = Password;<br />
}<br />
<br />
<br />
public void Connect() {<br />
if (pop3ConnectionState!=Pop3ConnectionStateEnum.Disconnected &&<br />
pop3ConnectionState!=Pop3ConnectionStateEnum.Closed && <br />
!isTimeoutReconnect) {<br />
CallWarning("connect", "", "Connect command received, but connection state is: " + pop3ConnectionState.ToString());<br />
} else {<br />
try {<br />
CallTrace(" Connect at port {0}", port);<br />
serverTcpConnection = new TcpClient(popServer, port);<br />
} catch (Exception ex) {<br />
throw new Pop3Exception("Connection to server "+ popServer + ", port " + port + " failed.\nRuntime Error: "+ex.ToString());<br />
}<br />
<br />
if (useSSL) {<br />
try {<br />
CallTrace(" Get SSL connection");<br />
pop3Stream = new SslStream(serverTcpConnection.GetStream(), false);<br />
pop3Stream.ReadTimeout = readTimeout;<br />
} catch (Exception ex) {<br />
throw new Pop3Exception("Server " + popServer + " found, but cannot get SSL data stream.\nRuntime Error: "+ex.ToString());<br />
}<br />
<br />
try {<br />
CallTrace(" Get SSL authentication");<br />
((SslStream)pop3Stream).AuthenticateAsClient(popServer);<br />
} catch (Exception ex) {<br />
throw new Pop3Exception("Server " + popServer + " found, but problem with SSL Authentication.\nRuntime Error: " + ex.ToString());<br />
}<br />
} else {<br />
try {<br />
CallTrace(" Get connection without SSL");<br />
pop3Stream = serverTcpConnection.GetStream();<br />
pop3Stream.ReadTimeout = readTimeout;<br />
} catch (Exception ex) {<br />
throw new Pop3Exception("Server " + popServer + " found, but cannot get data stream (without SSL).\nRuntime Error: "+ex.ToString());<br />
}<br />
}<br />
try {<br />
pop3StreamReader= new StreamReader(pop3Stream, Encoding.ASCII);<br />
} catch (Exception ex) {<br />
if (useSSL) {<br />
throw new Pop3Exception("Server " + popServer + " found, but cannot read from SSL stream.\nRuntime Error: " + ex.ToString());<br />
} else {<br />
throw new Pop3Exception("Server " + popServer + " found, but cannot read from stream (without SSL).\nRuntime Error: " + ex.ToString());<br />
}<br />
}<br />
<br />
string response;<br />
if (!readSingleLine(out response)) {<br />
throw new Pop3Exception("Server " + popServer + " not ready to start AUTHORIZATION.\nMessage: " + response);<br />
}<br />
setPop3ConnectionState(Pop3ConnectionStateEnum.Authorization);<br />
<br />
if (!executeCommand("USER "+ username, out response)) {<br />
throw new Pop3Exception("Server " + popServer + " doesn't accept username '" + username + "'.\nMessage: " + response);<br />
}<br />
<br />
if (!executeCommand("PASS " + password, out response)) {<br />
throw new Pop3Exception("Server " + popServer + " doesn't accept password '" + password + "' for user '" + username + "'.\nMessage: " + response);<br />
}<br />
<br />
setPop3ConnectionState(Pop3ConnectionStateEnum.Connected);<br />
}<br />
}<br />
<br />
<br />
public void Disconnect() {<br />
if (pop3ConnectionState==Pop3ConnectionStateEnum.Disconnected ||<br />
pop3ConnectionState==Pop3ConnectionStateEnum.Closed) {<br />
CallWarning("disconnect", "", "Disconnect received, but was already disconnected.");<br />
} else {<br />
try {<br />
string response;<br />
if (executeCommand("QUIT", out response)) {<br />
setPop3ConnectionState(Pop3ConnectionStateEnum.Closed);<br />
} else {<br />
CallWarning("Disconnect", response, "negative response from server while closing connection: " + response);<br />
setPop3ConnectionState(Pop3ConnectionStateEnum.Disconnected);<br />
}<br />
} finally {<br />
if (pop3Stream!=null) {<br />
pop3Stream.Close();<br />
}<br />
<br />
pop3StreamReader.Close();<br />
}<br />
}<br />
}<br />
<br />
<br />
public bool DeleteEmail(int msg_number) {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
string response;<br />
if (!executeCommand("DELE " + msg_number.ToString(), out response)) {<br />
CallWarning("DeleteEmail", response, "negative response for email (Id: {0}) delete request", msg_number);<br />
return false;<br />
}<br />
return true;<br />
}<br />
<br />
<br />
public bool GetEmailIdList(out List<int> EmailIds) {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
EmailIds = new List<int>();<br />
<br />
string response;<br />
if (!executeCommand("LIST", out response)) {<br />
CallWarning("GetEmailIdList", response, "negative response for email list request");<br />
return false;<br />
}<br />
<br />
int EmailId;<br />
while (readMultiLine(out response)) {<br />
if (int.TryParse(response.Split(' ')[0], out EmailId)) {<br />
EmailIds.Add(EmailId);<br />
} else {<br />
CallWarning("GetEmailIdList", response, "first characters should be integer (EmailId)");<br />
}<br />
}<br />
TraceFrom("{0} email ids received", EmailIds.Count);<br />
return true;<br />
}<br />
<br />
<br />
public int GetEmailSize(int msg_number) {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
string response;<br />
executeCommand("LIST " + msg_number.ToString(), out response);<br />
int EmailSize = 0;<br />
string[] responseSplit = response.Split(' ');<br />
if (responseSplit.Length<2 || !int.TryParse(responseSplit[2], out EmailSize)) {<br />
CallWarning("GetEmailSize", response, "'+OK int int' format expected (EmailId, EmailSize)");<br />
}<br />
<br />
return EmailSize;<br />
}<br />
<br />
<br />
public bool GetUniqueEmailIdList(out List<EmailUid> EmailIds) {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
EmailIds = new List<EmailUid>();<br />
<br />
string response;<br />
if (!executeCommand("UIDL ", out response)) {<br />
CallWarning("GetUniqueEmailIdList", response, "negative response for email list request");<br />
return false;<br />
}<br />
<br />
int EmailId;<br />
while (readMultiLine(out response)) {<br />
string[] responseSplit = response.Split(' ');<br />
if (responseSplit.Length<2) {<br />
CallWarning("GetUniqueEmailIdList", response, "response not in format 'int string'");<br />
} else if (!int.TryParse(responseSplit[0], out EmailId)) {<br />
CallWarning("GetUniqueEmailIdList", response, "first charaters should be integer (Unique EmailId)");<br />
} else {<br />
EmailIds.Add(new EmailUid(EmailId, responseSplit[1]));<br />
}<br />
}<br />
TraceFrom("{0} unique email ids received", EmailIds.Count);<br />
return true;<br />
}<br />
<br />
<br />
public bool GetUniqueEmailIdList(out SortedList<string, int> EmailIds) {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
EmailIds = new SortedList<string, int>();<br />
<br />
string response;<br />
if (!executeCommand("UIDL", out response)) {<br />
CallWarning("GetUniqueEmailIdList", response, "negative response for email list request");<br />
return false;<br />
}<br />
<br />
int EmailId;<br />
while (readMultiLine(out response)) {<br />
string[] responseSplit = response.Split(' ');<br />
if (responseSplit.Length<2) {<br />
CallWarning("GetUniqueEmailIdList", response, "response not in format 'int string'");<br />
} else if (!int.TryParse(responseSplit[0], out EmailId)) {<br />
CallWarning("GetUniqueEmailIdList", response, "first charaters should be integer (Unique EmailId)");<br />
} else {<br />
EmailIds.Add(responseSplit[1], EmailId);<br />
}<br />
}<br />
TraceFrom("{0} unique email ids received", EmailIds.Count);<br />
return true;<br />
}<br />
<br />
<br />
public int GetUniqueEmailId(EmailUid msg_number) {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
string response;<br />
executeCommand("LIST " + msg_number.ToString(), out response);<br />
int EmailSize = 0;<br />
string[] responseSplit = response.Split(' ');<br />
if (responseSplit.Length<2 || !int.TryParse(responseSplit[2], out EmailSize)) {<br />
CallWarning("GetEmailSize", response, "'+OK int int' format expected (EmailId, EmailSize)");<br />
}<br />
<br />
return EmailSize;<br />
}<br />
<br />
<br />
public bool NOOP() {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
string response;<br />
if (!executeCommand("NOOP", out response)) {<br />
CallWarning("NOOP", response, "negative response for NOOP request");<br />
return false;<br />
}<br />
return true;<br />
}<br />
<br />
protected bool isTraceRawEmail = false;<br />
<br />
<br />
protected StringBuilder RawEmailSB;<br />
<br />
<br />
public bool GetRawEmail(int MessageNo, out string EmailText) {<br />
if (!SendRetrCommand(MessageNo)) {<br />
EmailText = null;<br />
return false;<br />
}<br />
<br />
string response;<br />
int LineCounter = 0;<br />
if (RawEmailSB==null) {<br />
RawEmailSB = new StringBuilder(100000);<br />
} else {<br />
RawEmailSB.Length = 0;<br />
}<br />
isTraceRawEmail = true;<br />
while (readMultiLine(out response)) {<br />
LineCounter += 1;<br />
}<br />
EmailText = RawEmailSB.ToString();<br />
TraceFrom("email with {0} lines, {1} chars received", LineCounter.ToString(), EmailText.Length);<br />
return true;<br />
}<br />
<br />
<br />
public bool GetEmailHeader(int MessageNo, out string EmailHeader)<br />
{<br />
if (!SendTopCommand(MessageNo))<br />
{<br />
EmailHeader = null;<br />
return false;<br />
}<br />
<br />
string response;<br />
int LineCounter = 0;<br />
if (RawEmailSB == null)<br />
{<br />
RawEmailSB = new StringBuilder(100000);<br />
}<br />
else<br />
{<br />
RawEmailSB.Length = 0;<br />
}<br />
isTraceRawEmail = true;<br />
while (readMultiLine(out response))<br />
{<br />
LineCounter += 1;<br />
}<br />
EmailHeader = RawEmailSB.ToString();<br />
TraceFrom("email with {0} lines, {1} chars received", LineCounter.ToString(), EmailHeader.Length);<br />
return true;<br />
}<br />
<br />
<br />
<br />
<br />
public bool UndeleteAllEmails() {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
string response;<br />
return executeCommand("RSET", out response);<br />
}<br />
<br />
<br />
public bool GetMailboxStats(out int NumberOfMails, out int MailboxSize) {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
<br />
string response;<br />
NumberOfMails = 0;<br />
MailboxSize =0;<br />
if (executeCommand("STAT", out response)) {<br />
string[] responseParts = response.Split(' ');<br />
if (responseParts.Length<2) {<br />
throw new Pop3Exception("Server " + popServer + " sends illegally formatted response." +<br />
"\nExpected format: +OK int int" +<br />
"\nReceived response: " + response);<br />
}<br />
NumberOfMails = int.Parse(responseParts[1]);<br />
MailboxSize = int.Parse(responseParts[2]);<br />
return true;<br />
}<br />
return false;<br />
}<br />
<br />
<br />
protected bool SendRetrCommand(int MessageNo) {<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
string response;<br />
if (!executeCommand("RETR "+ MessageNo.ToString(), out response)) {<br />
CallWarning("GetRawEmail", response, "negative response for email (ID: {0}) request", MessageNo);<br />
return false;<br />
}<br />
return true;<br />
}<br />
<br />
protected bool SendTopCommand(int MessageNo)<br />
{<br />
EnsureState(Pop3ConnectionStateEnum.Connected);<br />
string response;<br />
if (!executeCommand("TOP "+MessageNo.ToString()+" 0", out response))<br />
{<br />
CallWarning("GetEmailHeader", response, "negative response for email (ID: {0}) request", MessageNo);<br />
return false;<br />
}<br />
return true;<br />
}<br />
<br />
<br />
<br />
<br />
<br />
<br />
public bool isDebug = false;<br />
private bool executeCommand(string command, out string response) {<br />
byte[] commandBytes = System.Text.Encoding.ASCII.GetBytes((command + CRLF).ToCharArray());<br />
CallTrace("Tx '{0}'", command);<br />
bool isSupressThrow = false;<br />
try {<br />
pop3Stream.Write(commandBytes, 0, commandBytes.Length);<br />
if (isDebug) {<br />
isDebug=false;<br />
throw new IOException("Test", new SocketException(10053));<br />
}<br />
} catch (IOException ex) {<br />
isSupressThrow = executeReconnect(ex, command, commandBytes);<br />
if (!isSupressThrow) {<br />
throw;<br />
}<br />
}<br />
pop3Stream.Flush();<br />
<br />
response = null;<br />
try {<br />
response = pop3StreamReader.ReadLine();<br />
} catch (IOException ex) {<br />
isSupressThrow = executeReconnect(ex, command, commandBytes);<br />
if (isSupressThrow) {<br />
response = pop3StreamReader.ReadLine();<br />
} else {<br />
throw;<br />
}<br />
}<br />
if (response==null) {<br />
throw new Pop3Exception("Server "+ popServer + " has not responded, timeout has occured.");<br />
}<br />
CallTrace("Rx '{0}'", response);<br />
return (response.Length>0 && response[0]=='+');<br />
}<br />
<br />
<br />
private bool executeReconnect(IOException ex, string command, byte[] commandBytes) {<br />
if (ex.InnerException!=null && ex.InnerException is SocketException) {<br />
SocketException innerEx = (SocketException)ex.InnerException;<br />
if (innerEx.ErrorCode==10053) {<br />
CallWarning("ExecuteCommand", "", "probably timeout occured");<br />
if (isAutoReconnect) {<br />
isTimeoutReconnect = true;<br />
try {<br />
CallTrace(" try to auto reconnect");<br />
Connect();<br />
<br />
CallTrace(" reconnect successful, try to resend command");<br />
CallTrace("Tx '{0}'", command);<br />
pop3Stream.Write(commandBytes, 0, commandBytes.Length);<br />
pop3Stream.Flush();<br />
return true;<br />
} finally {<br />
isTimeoutReconnect = false;<br />
}<br />
<br />
}<br />
}<br />
}<br />
return false;<br />
}<br />
<br />
<br />
<br />
<br />
<br />
protected bool readSingleLine(out string response) {<br />
response = null;<br />
try {<br />
response = pop3StreamReader.ReadLine();<br />
} catch (Exception ex) {<br />
string s = ex.Message;<br />
}<br />
if (response==null) {<br />
throw new Pop3Exception("Server "+ popServer + " has not responded, timeout has occured.");<br />
}<br />
CallTrace("Rx '{0}'", response);<br />
return (response.Length>0 && response[0]=='+');<br />
}<br />
<br />
<br />
protected bool readMultiLine(out string response) {<br />
response = null;<br />
response = pop3StreamReader.ReadLine();<br />
if (response==null) {<br />
throw new Pop3Exception("Server "+ popServer + " has not responded, probably timeout has occured.");<br />
}<br />
if (isTraceRawEmail) {<br />
RawEmailSB.Append(response + CRLF);<br />
}<br />
if (response.Length>0 && response[0]=='.') {<br />
if (response==".") {<br />
return false;<br />
}<br />
response = response.Substring(1, response.Length-1);<br />
}<br />
return true;<br />
}<br />
<br />
}<br />
}<br />
}<br />
<br />
"Gödel proved that any formal system that defines the primitive recursive functions must be either incomplete or inconsistent. In particular one could not prove from within the system that the system itself was consistent even though the question could be formulated within the system."
|