bool _submitMessage(int recipientIndex, MailTask mailTask)
        {
            if (!_trafficController.PrepareIncreaseConnection())
            {
                _trafficController.Rollback();
                return(false);
            }

            if (!_trafficController.PrepareIncreaseMessage())
            {
                _trafficController.Rollback();
                return(false);
            }

            SendMailThreadState state = new SendMailThreadState();

            state.Server = mailTask.BuildServer();
            state.Mail   = mailTask.BuildMail();

            state.Mail.TextBody = state.Mail.TextBody.Replace("[$sender]", state.Mail.From.ToString());
            state.Mail.TextBody = state.Mail.TextBody.Replace("[$rcpt]", state.Mail.To.ToString());
            state.Mail.TextBody = state.Mail.TextBody.Replace("[$subject]", state.Mail.Subject.ToString());

            // even you can add different attachment for different recipient here.
            state.RecipientIndex = recipientIndex;

            try
            {
                Interlocked.Increment(ref _threadCounter);
                ThreadPool.QueueUserWorkItem(this._sendThreadProc, state);
                _trafficController.Commit();

                return(true);
            }
            catch
            {
                Interlocked.Decrement(ref _threadCounter);
                _trafficController.Rollback();
                return(false);
            }
        }
        void _sendThreadProc(object state)
        {
            SendMailThreadState threadState = (SendMailThreadState)state;
            int recipientIndex = threadState.RecipientIndex;

            RecipientStatus status = new RecipientStatus();

            status.RecipientIndex = recipientIndex;
            status.Recipient      = threadState.Mail.To.ToString();

            try
            {
                SmtpClient smtp = new SmtpClient();
                smtp.Tag = status;

                // Catching the following events is not necessary,
                // just make the application more user friendly.
                // If you use the object in asp.net/windows service or non-gui application,
                // You need not to catch the following events.
                // To learn more detail, please refer to the code in EASendMail EventHandler region
                smtp.OnIdle              += new SmtpClient.OnIdleEventHandler(OnIdle);
                smtp.OnAuthorized        += new SmtpClient.OnAuthorizedEventHandler(OnAuthorized);
                smtp.OnConnected         += new SmtpClient.OnConnectedEventHandler(OnConnected);
                smtp.OnSecuring          += new SmtpClient.OnSecuringEventHandler(OnSecuring);
                smtp.OnSendingDataStream += new SmtpClient.OnSendingDataStreamEventHandler(OnSendingDataStream);

                status.Status = "Connecting server ...";
                _updateRecipientStatus(status);

                smtp.SendMail(threadState.Server, threadState.Mail);

                status.Status    = "Succeeded";
                status.Completed = true;

                _updateRecipientStatus(status);
                _updateResultCounter(true);

                if (UpdateResult != null)
                {
                    string recipientAddress = (threadState.Mail.To[0] as MailAddress).Address;
                    UpdateResult(threadState.DbTaskId, true, recipientAddress, "Completed");
                }
            }
            catch (Exception ep)
            {
                status.Status    = ep.Message;
                status.HasError  = true;
                status.Completed = true;

                _updateRecipientStatus(status);
                _updateResultCounter(false);

                if (UpdateResult != null)
                {
                    string recipientAddress = (threadState.Mail.To[0] as MailAddress).Address;
                    UpdateResult(threadState.DbTaskId, false, recipientAddress, ep.Message);
                }
            }
            finally
            {
                Interlocked.Decrement(ref _threadCounter);
                _trafficController.DecreaseConnection();
            }
        }