SmtpClient.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / Mail / SmtpClient.cs / 1305376 / SmtpClient.cs

                            namespace System.Net.Mail 
{

    using System;
    using System.IO; 
    using System.Net;
    using System.Collections; 
    using System.ComponentModel; 
    using System.Configuration;
    using System.Net.Configuration; 
    using System.Threading;
    using System.Security;
    using System.Security.Permissions;
    using System.Security.Authentication; 
    using System.Security.Cryptography.X509Certificates;
    using System.Net.NetworkInformation; 
    using System.Runtime.Versioning; 
    using System.Text;
 
    public delegate void SendCompletedEventHandler(object sender, AsyncCompletedEventArgs e);

    public enum SmtpDeliveryMethod {
        Network, 
        SpecifiedPickupDirectory,
#if !FEATURE_PAL 
        PickupDirectoryFromIis 
#endif
    } 


    public class SmtpClient : IDisposable {
 
        string host;
        int port; 
        bool inCall; 
        bool cancelled;
        bool timedOut; 
        string targetName = null;
        SmtpDeliveryMethod deliveryMethod = SmtpDeliveryMethod.Network;
        string pickupDirectoryLocation = null;
        SmtpTransport transport; 
        MailMessage message; //required to prevent premature finalization
        MailWriter writer; 
        MailAddressCollection recipients; 
        SendOrPostCallback onSendCompletedDelegate;
        Timer timer; 
        static MailSettingsSectionGroupInternal mailConfiguration;
        ContextAwareResult operationCompletedResult = null;
        AsyncOperation asyncOp = null;
        static AsyncCallback _ContextSafeCompleteCallback = new AsyncCallback(ContextSafeCompleteCallback); 
        static int defaultPort = 25;
        internal string clientDomain = null; 
        bool disposed = false; 
        // true if the host and port change between calls to send or GetServicePoint
        bool servicePointChanged = false; 
        ServicePoint servicePoint = null;
        // ports above this limit are invalid
        const int maxPortValue = 65535;
 
        public event SendCompletedEventHandler SendCompleted;
 
        public SmtpClient() { 
            if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "");
            try { 
                Initialize();
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this);
            } 
        }
 
        public SmtpClient(string host) { 
            if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "host=" + host);
            try { 
                this.host = host;
                Initialize();
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this); 
            }
        } 
 
        //?? should port throw or just default on 0?
        public SmtpClient(string host, int port) { 
            if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "host=" + host + ", port=" + port);
            try {
                if (port < 0) {
                    throw new ArgumentOutOfRangeException("port"); 
                }
 
                this.host = host; 
                this.port = port;
                Initialize(); 
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this);
            }
        } 

        void Initialize() { 
            if (port == defaultPort || port == 0) { 
                new SmtpPermission(SmtpAccess.Connect).Demand();
            } 
            else {
                new SmtpPermission(SmtpAccess.ConnectToUnrestrictedPort).Demand();
            }
 
            transport = new SmtpTransport(this);
            if (Logging.On) Logging.Associate(Logging.Web, this, transport); 
            onSendCompletedDelegate = new SendOrPostCallback(SendCompletedWaitCallback); 

            if (MailConfiguration.Smtp != null) 
            {
                if (MailConfiguration.Smtp.Network != null)
                {
                    if (host == null || host.Length == 0) { 
                        host = MailConfiguration.Smtp.Network.Host;
                    } 
                    if (port == 0) { 
                        port = MailConfiguration.Smtp.Network.Port;
                    } 

                    transport.Credentials = MailConfiguration.Smtp.Network.Credential;
                    transport.EnableSsl = MailConfiguration.Smtp.Network.EnableSsl;
 
                    if (MailConfiguration.Smtp.Network.TargetName != null)
                        targetName = MailConfiguration.Smtp.Network.TargetName; 
 
                    // If the config file contains a domain to be used for the
                    // domain element in the client's EHLO or HELO message, 
                    // use it.
                    //
                    // We do not validate whether the domain specified is valid.
                    // It is up to the administrators or user to use the right 
                    // value for their scenario.
                    // 
                    // Note: per section 4.1.4 of RFC2821, the domain element of 
                    // the HELO/EHLO should be used for logging purposes. An
                    // SMTP server should not decide to route an email based on 
                    // this value.
                    clientDomain = MailConfiguration.Smtp.Network.ClientDomain;
                }
 
                deliveryMethod = MailConfiguration.Smtp.DeliveryMethod;
                if (MailConfiguration.Smtp.SpecifiedPickupDirectory != null) 
                    pickupDirectoryLocation = MailConfiguration.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation; 
            }
 
            if (host != null && host.Length != 0) {
                host = host.Trim();
            }
 
            if (port == 0) {
                port = defaultPort; 
            } 

            if (this.targetName == null) 
                targetName = "SMTPSVC/" + host;

            if (clientDomain == null) {
                // We use the local host name as the default client domain 
                // for the client's EHLO or HELO message. This limits the
                // information about the host that we share. Additionally, the 
                // FQDN is not available to us or useful to the server (internal 
                // machine connecting to public server).
                // 
                // We need to strip out any non-ASCII characters from the local host name.
                // SMTP RFC's require ASCII only host names in the HELO/EHLO message.
                // If we end up with no characters left, we use the string "LocalHost".  This
                // matches Outlook behavior. 
                string clientDomainRaw = IPGlobalProperties.InternalGetIPGlobalProperties().HostName;
                StringBuilder sb = new StringBuilder(); 
                char ch; 
                for (int i = 0; i < clientDomainRaw.Length; i++) {
                    ch = clientDomainRaw[i]; 
                    if ((ushort)ch <= 0x7F)
                        sb.Append(ch);
                }
                if (sb.Length > 0) 
                    clientDomain = sb.ToString();
                else 
                    clientDomain = "LocalHost"; 
            }
        } 


        public string Host {
            get { 
                return host;
            } 
            set { 

                if (InCall) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
                }

                if (value == null) 
                {
                    throw new ArgumentNullException("value"); 
                } 

                if (value == String.Empty) 
                {
                    throw new ArgumentException(SR.GetString(SR.net_emptystringset), "value");
                }
 
                value = value.Trim();
 
                if (value != host) 
                {
                    host = value; 
                    servicePointChanged = true;
                }
            }
        } 

 
        public int Port { 
            get {
                return port; 
            }
            set {
                if (InCall) {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend)); 
                }
 
                if (value <= 0) { 
                    throw new ArgumentOutOfRangeException("value");
                } 

                if (value != defaultPort) {
                    new SmtpPermission(SmtpAccess.ConnectToUnrestrictedPort).Demand();
                } 

                if (value != port) { 
                    port = value; 
                    servicePointChanged = true;
                } 
            }
        }

 
        public bool UseDefaultCredentials {
            get { 
                return (transport.Credentials is SystemNetworkCredential) ? true : false; 
            }
            set { 
                if (InCall) {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
                }
 
                transport.Credentials = value ? CredentialCache.DefaultNetworkCredentials : null;
            } 
        } 

 
        public ICredentialsByHost Credentials {
            get {
                return transport.Credentials;
            } 
            set {
                if (InCall) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend)); 
                }
 
                transport.Credentials = value;
            }
        }
 

 
        public int Timeout { 
            get {
                return transport.Timeout; 
            }
            set {
                if (InCall) {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend)); 
                }
 
                if (value < 0) 
                {
                    throw new ArgumentOutOfRangeException("value"); 
                }

                transport.Timeout = value;
            } 
        }
 
 
        public ServicePoint ServicePoint {
            get { 
                CheckHostAndPort();
                if (servicePoint == null || servicePointChanged) {
                    servicePoint = ServicePointManager.FindServicePoint(host, port);
                    // servicePoint is now correct for current host and port 
                    servicePointChanged = false;
                } 
                return servicePoint; 
            }
        } 

        public SmtpDeliveryMethod DeliveryMethod {
            get {
                return deliveryMethod; 
            }
            set { 
                deliveryMethod = value; 
            }
        } 


        public string PickupDirectoryLocation {
            [ResourceExposure(ResourceScope.Machine)] 
            [ResourceConsumption(ResourceScope.Machine)]
            get { 
                return pickupDirectoryLocation; 
            }
            [ResourceExposure(ResourceScope.Machine)] 
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                pickupDirectoryLocation = value;
            } 
        }
        ///  
        ///    Set to true if we need SSL 
        /// 
        public bool EnableSsl { 
            get {
                return transport.EnableSsl;
            }
            set { 
                transport.EnableSsl = value;
            } 
        } 

        ///  
        /// Certificates used by the client for establishing an SSL connection with the server.
        /// 
        public X509CertificateCollection ClientCertificates {
            get { 
                return transport.ClientCertificates;
            } 
        } 

        public string TargetName { 
            set { this.targetName = value; }
            get { return this.targetName; }
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        internal MailWriter GetFileMailWriter(string pickupDirectory) 
        {
            if (Logging.On) Logging.PrintInfo(Logging.Web, "SmtpClient.Send() pickupDirectory=" + pickupDirectory); 
            if (!Path.IsPathRooted(pickupDirectory))
                throw new SmtpException(SR.GetString(SR.SmtpNeedAbsolutePickupDirectory));
            string filename;
            string pathAndFilename; 
            while (true) {
                filename = Guid.NewGuid().ToString() + ".eml"; 
                pathAndFilename = Path.Combine(pickupDirectory, filename); 
                if (!File.Exists(pathAndFilename))
                    break; 
            }

            FileStream fileStream = new FileStream(pathAndFilename, FileMode.CreateNew);
            return new MailWriter(fileStream); 
        }
 
        protected void OnSendCompleted(AsyncCompletedEventArgs e) 
        {
            if (SendCompleted != null) { 
                SendCompleted(this, e);
            }
        }
 
        void SendCompletedWaitCallback(object operationState) {
            OnSendCompleted((AsyncCompletedEventArgs)operationState); 
        } 

 
        public void Send(string from, string recipients, string subject, string body) {
            if (disposed) {
                throw new ObjectDisposedException(this.GetType().FullName);
            } 
            //validation happends in MailMessage constructor
            MailMessage mailMessage = new MailMessage(from, recipients, subject, body); 
            Send(mailMessage); 
        }
 

        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        public void Send(MailMessage message) { 
            if (Logging.On) Logging.Enter(Logging.Web, this, "Send", message);
            if (disposed) { 
                throw new ObjectDisposedException(this.GetType().FullName); 
            }
            try { 
                if (Logging.On) Logging.PrintInfo(Logging.Web, this, "Send", "DeliveryMethod=" + DeliveryMethod.ToString());
                if (Logging.On) Logging.Associate(Logging.Web, this, message);
                SmtpFailedRecipientException recipientException = null;
 
                if (InCall) {
                    throw new InvalidOperationException(SR.GetString(SR.net_inasync)); 
                } 

                if (message == null) { 
                    throw new ArgumentNullException("message");
                }

                if (DeliveryMethod == SmtpDeliveryMethod.Network) 
                    CheckHostAndPort();
 
                MailAddressCollection recipients = new MailAddressCollection(); 

                if (message.From == null) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpFromRequired));
                }

                if (message.To != null) { 
                    foreach (MailAddress address in message.To) {
                        recipients.Add(address); 
                    } 
                }
                if (message.Bcc != null) { 
                    foreach (MailAddress address in message.Bcc) {
                        recipients.Add(address);
                    }
                } 
                if (message.CC != null) {
                    foreach (MailAddress address in message.CC) { 
                        recipients.Add(address); 
                    }
                } 

                if (recipients.Count == 0) {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpRecipientRequired));
                } 

                transport.IdentityRequired = false;  // everything completes on the same thread. 
 
                try {
                    InCall = true; 
                    timedOut = false;
                    timer = new Timer(new TimerCallback(this.TimeOutCallback), null, Timeout, Timeout);

                    MailWriter writer; 
                    switch (DeliveryMethod) {
                        case SmtpDeliveryMethod.SpecifiedPickupDirectory: 
                            if (EnableSsl) 
                                throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl));
                            writer = GetFileMailWriter(PickupDirectoryLocation); 
                            break;
#if !FEATURE_PAL
                        case SmtpDeliveryMethod.PickupDirectoryFromIis:
                            if (EnableSsl) 
                                throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl));
                            writer = GetFileMailWriter(IisPickupDirectory.GetPickupDirectory()); 
                            break; 
#endif // !FEATURE_PAL
                        case SmtpDeliveryMethod.Network: 
                        default:
                            GetConnection();
                            writer = transport.SendMail(message.Sender != null ? message.Sender : message.From, recipients, message.BuildDeliveryStatusNotificationString(), out recipientException);
                            break; 
                    }
                    this.message = message; 
                    message.Send(writer, DeliveryMethod != SmtpDeliveryMethod.Network); 
                    writer.Close();
                    transport.ReleaseConnection(); 

                    //throw if we couldn't send to any of the recipients
                    if (DeliveryMethod == SmtpDeliveryMethod.Network)
                        if (recipientException != null) 
                            throw recipientException;
                } 
                catch (Exception e) { 

                    if (Logging.On) Logging.Exception(Logging.Web, this, "Send", e); 


                    if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) {
                        throw; 
                    }
 
 
                    Abort();
                    if (timedOut) { 
                        throw new SmtpException(SR.GetString(SR.net_timeout));
                    }

                    if (e is SecurityException || 
                        e is AuthenticationException ||
                        e is SmtpException) 
                    { 
                        throw;
                    } 

                    throw new SmtpException(SR.GetString(SR.SmtpSendMailFailure), e);
                }
                finally { 
                    InCall = false;
                    if (timer != null) { 
                        timer.Dispose(); 
                    }
                } 
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, this, "Send", null);
            }
        } 

 
 
        [HostProtection(ExternalThreading = true)]
        public void SendAsync(string from, string recipients, string subject, string body, object userToken) { 
            if (disposed) {
                throw new ObjectDisposedException(this.GetType().FullName);
            }
            SendAsync(new MailMessage(from, recipients, subject, body), userToken); 
        }
 
 
        [HostProtection(ExternalThreading = true)]
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        public void SendAsync(MailMessage message, object userToken) {
            if (disposed) {
                throw new ObjectDisposedException(this.GetType().FullName); 
            }
            if (Logging.On) Logging.Enter(Logging.Web, this, "SendAsync", "DeliveryMethod=" + DeliveryMethod.ToString()); 
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync Transport#" + ValidationHelper.HashString(transport)); 
            try {
                if (InCall) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_inasync));
                }

                if (message == null) { 
                    throw new ArgumentNullException("message");
                } 
 
                if (DeliveryMethod == SmtpDeliveryMethod.Network)
                    CheckHostAndPort(); 

                recipients = new MailAddressCollection();

                if (message.From == null) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpFromRequired));
                } 
 
                if (message.To != null) {
                    foreach (MailAddress address in message.To) { 
                        recipients.Add(address);
                    }
                }
                if (message.Bcc != null) { 
                    foreach (MailAddress address in message.Bcc) {
                        recipients.Add(address); 
                    } 
                }
                if (message.CC != null) { 
                    foreach (MailAddress address in message.CC) {
                        recipients.Add(address);
                    }
                } 

                if (recipients.Count == 0) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpRecipientRequired)); 
                }
 
                try {
                    InCall = true;
                    cancelled = false;
                    this.message = message; 

#if !FEATURE_PAL 
                    CredentialCache cache; 
                    // Skip token capturing if no credentials are used or they don't include a default one.
                    // Also do capture the token if ICredential is not of CredentialCache type so we don't know what the exact credential response will be. 
                    transport.IdentityRequired = Credentials != null && ComNetOS.IsWinNt && (Credentials is SystemNetworkCredential || (cache = Credentials as CredentialCache) == null || cache.IsDefaultInCache);
#endif // !FEATURE_PAL

                    asyncOp = AsyncOperationManager.CreateOperation(userToken); 
                    switch (DeliveryMethod) {
                        case SmtpDeliveryMethod.SpecifiedPickupDirectory: 
                            { 
                                if (EnableSsl)
                                    throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl)); 
                                writer = GetFileMailWriter(PickupDirectoryLocation);
                                message.Send(writer, DeliveryMethod != SmtpDeliveryMethod.Network);

                                if (writer != null) 
                                    writer.Close();
 
                                transport.ReleaseConnection(); 
                                AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, asyncOp.UserSuppliedState);
                                InCall = false; 
                                asyncOp.PostOperationCompleted(onSendCompletedDelegate, eventArgs);
                                break;
                            }
#if !FEATURE_PAL 
                        case SmtpDeliveryMethod.PickupDirectoryFromIis:
                            { 
                                if (EnableSsl) 
                                    throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl));
                                writer = GetFileMailWriter(IisPickupDirectory.GetPickupDirectory()); 
                                message.Send(writer, DeliveryMethod != SmtpDeliveryMethod.Network);

                                if (writer != null)
                                    writer.Close(); 

                                transport.ReleaseConnection(); 
                                AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, asyncOp.UserSuppliedState); 
                                InCall = false;
                                asyncOp.PostOperationCompleted(onSendCompletedDelegate, eventArgs); 
                                break;
                            }
#endif // !FEATURE_PAL
 
                        case SmtpDeliveryMethod.Network:
                        default: 
                            operationCompletedResult = new ContextAwareResult(transport.IdentityRequired, true, null, this, _ContextSafeCompleteCallback); 
                            lock (operationCompletedResult.StartPostingAsyncOp())
                            { 
                                GlobalLog.Print("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync calling BeginConnect.  Transport#" + ValidationHelper.HashString(transport));
                                transport.BeginGetConnection(ServicePoint, operationCompletedResult, ConnectCallback, operationCompletedResult);
                                operationCompletedResult.FinishPostingAsyncOp();
                            } 
                            break;
                    } 
 
                }
                catch (Exception e) { 
                    InCall = false;

                    if (Logging.On) Logging.Exception(Logging.Web, this, "Send", e);
 
                    if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) {
                        throw; 
                    } 

                    Abort(); 
                    if (timedOut) {
                        throw new SmtpException(SR.GetString(SR.net_timeout));
                    }
 
                    if (e is SecurityException ||
                        e is AuthenticationException || 
                        e is SmtpException) 
                    {
                        throw; 
                    }

                    throw new SmtpException(SR.GetString(SR.SmtpSendMailFailure), e);
                } 
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, this, "SendAsync", null); 
                GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync"); 
            }
        } 


        public void SendAsyncCancel() {
            if (disposed) { 
                throw new ObjectDisposedException(this.GetType().FullName);
            } 
            if (Logging.On) Logging.Enter(Logging.Web, this, "SendAsyncCancel", null); 
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel");
            try { 
                if (!InCall || cancelled) {
                    return;
                }
 
                cancelled = true;
                Abort(); 
            } finally { 
                if (Logging.On) Logging.Exit(Logging.Web, this, "SendAsyncCancel", null);
                GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel"); 
            }
        }

 
        //*********************************
        // private methods 
        //******************************** 
        internal bool InCall {
            get { 
                return inCall;
            }
            set {
                inCall = value; 
            }
        } 
 
        internal static MailSettingsSectionGroupInternal MailConfiguration {
            get { 
                if (mailConfiguration == null) {
                    mailConfiguration = MailSettingsSectionGroupInternal.GetSection();
                }
                return mailConfiguration; 
            }
        } 
 

        void CheckHostAndPort() { 

            if (host == null || host.Length == 0) {
                throw new InvalidOperationException(SR.GetString(SR.UnspecifiedHost));
            } 
            if (port <= 0 || port > maxPortValue) {
                throw new InvalidOperationException(SR.GetString(SR.InvalidPort)); 
            } 
        }
 

        void TimeOutCallback(object state) {
            if (!timedOut) {
                timedOut = true; 
                Abort();
            } 
        } 

 
        void Complete(Exception exception, IAsyncResult result) {
            ContextAwareResult operationCompletedResult = (ContextAwareResult)result.AsyncState;
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete");
            try { 
                if (cancelled) {
                    //any exceptions were probably caused by cancellation, clear it. 
                    exception = null; 
                    Abort();
                } 
                // A failed recipient exception is benign
                else if (exception != null && (!(exception is SmtpFailedRecipientException) || ((SmtpFailedRecipientException)exception).fatal))
                {
                    GlobalLog.Print("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete Exception: " + exception.ToString()); 
                    Abort();
 
                    if (!(exception is SmtpException)) { 
                        exception = new SmtpException(SR.GetString(SR.SmtpSendMailFailure), exception);
                    } 
                }
                else {
                    if (writer != null) {
                        writer.Close(); 
                    }
                    transport.ReleaseConnection(); 
                } 
            }
            finally { 
                operationCompletedResult.InvokeCallback(exception);
            }
            GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete");
        } 

        static void ContextSafeCompleteCallback(IAsyncResult ar) 
        { 
            ContextAwareResult result = (ContextAwareResult)ar;
            SmtpClient client = (SmtpClient)ar.AsyncState; 
            Exception exception = result.Result as Exception;
            AsyncOperation asyncOp = client.asyncOp;
            AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(exception, client.cancelled, asyncOp.UserSuppliedState);
            client.InCall = false; 
            asyncOp.PostOperationCompleted(client.onSendCompletedDelegate, eventArgs);
        } 
 
        /*
          void DisconnectCallback(IAsyncResult result) { 
              SmtpClient client = (SmtpClient)result.AsyncState;

              try {
                  client.transport.EndDisconnect(result); 
              }
              catch (Exception e) { 
                  Complete(e); 
                  return;
              } 
              Complete(null);
          }
                */
 
        void SendMessageCallback(IAsyncResult result) {
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback"); 
            try { 
                message.EndSend(result);
                Complete(null, result); 
            }
            catch (Exception e) {
                Complete(e, result);
            } 
            GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback");
        } 
 

        void SendMailCallback(IAsyncResult result) { 
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
            try {
                writer = transport.EndSendMail(result);
            } 
            catch (Exception e)
            { 
                // Note the difference between the singular and plural FailedRecipient exceptions. 
                // Only fail immediately if we couldn't send to any recipients.
                if (!(e is SmtpFailedRecipientException) || ((SmtpFailedRecipientException)e).fatal) 
                {
                    Complete(e, result);
                    GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
                    return; 
                }
            } 
            try { 
                if (cancelled) {
                    Complete(null, result); 
                }
                else {
                    message.BeginSend(writer, DeliveryMethod != SmtpDeliveryMethod.Network, new AsyncCallback(SendMessageCallback), result.AsyncState);
                } 
            }
            catch (Exception e) { 
                Complete(e, result); 
            }
            GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback"); 
        }


        void ConnectCallback(IAsyncResult result) { 
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::ConnectCallback");
            try { 
                transport.EndGetConnection(result); 
                if (cancelled) {
                    Complete(null, result); 
                }
                else {
                    transport.BeginSendMail(message.Sender != null ? message.Sender : message.From, recipients, message.BuildDeliveryStatusNotificationString(), new AsyncCallback(SendMailCallback), result.AsyncState);
                } 
            }
            catch (Exception e) { 
                Complete(e, result); 
            }
            GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::ConnectCallback"); 
        }


        void GetConnection() { 
            if (!transport.IsConnected) {
                transport.GetConnection(ServicePoint); 
            } 
        }
 

        void Abort() {
            try {
                transport.Abort(); 
            }
            catch { 
            } 
        }
 
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        } 

        protected virtual void Dispose(bool disposing) { 
            if (disposing && !disposed ) { 
                if (InCall && !cancelled) {
                    cancelled = true; 
                    Abort();
                }

                if (transport != null) { 
                    transport.CloseIdleConnections(ServicePoint);
                } 
 
                if (timer != null) {
                    timer.Dispose(); 
                }

                disposed = true;
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
namespace System.Net.Mail 
{

    using System;
    using System.IO; 
    using System.Net;
    using System.Collections; 
    using System.ComponentModel; 
    using System.Configuration;
    using System.Net.Configuration; 
    using System.Threading;
    using System.Security;
    using System.Security.Permissions;
    using System.Security.Authentication; 
    using System.Security.Cryptography.X509Certificates;
    using System.Net.NetworkInformation; 
    using System.Runtime.Versioning; 
    using System.Text;
 
    public delegate void SendCompletedEventHandler(object sender, AsyncCompletedEventArgs e);

    public enum SmtpDeliveryMethod {
        Network, 
        SpecifiedPickupDirectory,
#if !FEATURE_PAL 
        PickupDirectoryFromIis 
#endif
    } 


    public class SmtpClient : IDisposable {
 
        string host;
        int port; 
        bool inCall; 
        bool cancelled;
        bool timedOut; 
        string targetName = null;
        SmtpDeliveryMethod deliveryMethod = SmtpDeliveryMethod.Network;
        string pickupDirectoryLocation = null;
        SmtpTransport transport; 
        MailMessage message; //required to prevent premature finalization
        MailWriter writer; 
        MailAddressCollection recipients; 
        SendOrPostCallback onSendCompletedDelegate;
        Timer timer; 
        static MailSettingsSectionGroupInternal mailConfiguration;
        ContextAwareResult operationCompletedResult = null;
        AsyncOperation asyncOp = null;
        static AsyncCallback _ContextSafeCompleteCallback = new AsyncCallback(ContextSafeCompleteCallback); 
        static int defaultPort = 25;
        internal string clientDomain = null; 
        bool disposed = false; 
        // true if the host and port change between calls to send or GetServicePoint
        bool servicePointChanged = false; 
        ServicePoint servicePoint = null;
        // ports above this limit are invalid
        const int maxPortValue = 65535;
 
        public event SendCompletedEventHandler SendCompleted;
 
        public SmtpClient() { 
            if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "");
            try { 
                Initialize();
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this);
            } 
        }
 
        public SmtpClient(string host) { 
            if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "host=" + host);
            try { 
                this.host = host;
                Initialize();
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this); 
            }
        } 
 
        //?? should port throw or just default on 0?
        public SmtpClient(string host, int port) { 
            if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "host=" + host + ", port=" + port);
            try {
                if (port < 0) {
                    throw new ArgumentOutOfRangeException("port"); 
                }
 
                this.host = host; 
                this.port = port;
                Initialize(); 
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this);
            }
        } 

        void Initialize() { 
            if (port == defaultPort || port == 0) { 
                new SmtpPermission(SmtpAccess.Connect).Demand();
            } 
            else {
                new SmtpPermission(SmtpAccess.ConnectToUnrestrictedPort).Demand();
            }
 
            transport = new SmtpTransport(this);
            if (Logging.On) Logging.Associate(Logging.Web, this, transport); 
            onSendCompletedDelegate = new SendOrPostCallback(SendCompletedWaitCallback); 

            if (MailConfiguration.Smtp != null) 
            {
                if (MailConfiguration.Smtp.Network != null)
                {
                    if (host == null || host.Length == 0) { 
                        host = MailConfiguration.Smtp.Network.Host;
                    } 
                    if (port == 0) { 
                        port = MailConfiguration.Smtp.Network.Port;
                    } 

                    transport.Credentials = MailConfiguration.Smtp.Network.Credential;
                    transport.EnableSsl = MailConfiguration.Smtp.Network.EnableSsl;
 
                    if (MailConfiguration.Smtp.Network.TargetName != null)
                        targetName = MailConfiguration.Smtp.Network.TargetName; 
 
                    // If the config file contains a domain to be used for the
                    // domain element in the client's EHLO or HELO message, 
                    // use it.
                    //
                    // We do not validate whether the domain specified is valid.
                    // It is up to the administrators or user to use the right 
                    // value for their scenario.
                    // 
                    // Note: per section 4.1.4 of RFC2821, the domain element of 
                    // the HELO/EHLO should be used for logging purposes. An
                    // SMTP server should not decide to route an email based on 
                    // this value.
                    clientDomain = MailConfiguration.Smtp.Network.ClientDomain;
                }
 
                deliveryMethod = MailConfiguration.Smtp.DeliveryMethod;
                if (MailConfiguration.Smtp.SpecifiedPickupDirectory != null) 
                    pickupDirectoryLocation = MailConfiguration.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation; 
            }
 
            if (host != null && host.Length != 0) {
                host = host.Trim();
            }
 
            if (port == 0) {
                port = defaultPort; 
            } 

            if (this.targetName == null) 
                targetName = "SMTPSVC/" + host;

            if (clientDomain == null) {
                // We use the local host name as the default client domain 
                // for the client's EHLO or HELO message. This limits the
                // information about the host that we share. Additionally, the 
                // FQDN is not available to us or useful to the server (internal 
                // machine connecting to public server).
                // 
                // We need to strip out any non-ASCII characters from the local host name.
                // SMTP RFC's require ASCII only host names in the HELO/EHLO message.
                // If we end up with no characters left, we use the string "LocalHost".  This
                // matches Outlook behavior. 
                string clientDomainRaw = IPGlobalProperties.InternalGetIPGlobalProperties().HostName;
                StringBuilder sb = new StringBuilder(); 
                char ch; 
                for (int i = 0; i < clientDomainRaw.Length; i++) {
                    ch = clientDomainRaw[i]; 
                    if ((ushort)ch <= 0x7F)
                        sb.Append(ch);
                }
                if (sb.Length > 0) 
                    clientDomain = sb.ToString();
                else 
                    clientDomain = "LocalHost"; 
            }
        } 


        public string Host {
            get { 
                return host;
            } 
            set { 

                if (InCall) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
                }

                if (value == null) 
                {
                    throw new ArgumentNullException("value"); 
                } 

                if (value == String.Empty) 
                {
                    throw new ArgumentException(SR.GetString(SR.net_emptystringset), "value");
                }
 
                value = value.Trim();
 
                if (value != host) 
                {
                    host = value; 
                    servicePointChanged = true;
                }
            }
        } 

 
        public int Port { 
            get {
                return port; 
            }
            set {
                if (InCall) {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend)); 
                }
 
                if (value <= 0) { 
                    throw new ArgumentOutOfRangeException("value");
                } 

                if (value != defaultPort) {
                    new SmtpPermission(SmtpAccess.ConnectToUnrestrictedPort).Demand();
                } 

                if (value != port) { 
                    port = value; 
                    servicePointChanged = true;
                } 
            }
        }

 
        public bool UseDefaultCredentials {
            get { 
                return (transport.Credentials is SystemNetworkCredential) ? true : false; 
            }
            set { 
                if (InCall) {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
                }
 
                transport.Credentials = value ? CredentialCache.DefaultNetworkCredentials : null;
            } 
        } 

 
        public ICredentialsByHost Credentials {
            get {
                return transport.Credentials;
            } 
            set {
                if (InCall) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend)); 
                }
 
                transport.Credentials = value;
            }
        }
 

 
        public int Timeout { 
            get {
                return transport.Timeout; 
            }
            set {
                if (InCall) {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend)); 
                }
 
                if (value < 0) 
                {
                    throw new ArgumentOutOfRangeException("value"); 
                }

                transport.Timeout = value;
            } 
        }
 
 
        public ServicePoint ServicePoint {
            get { 
                CheckHostAndPort();
                if (servicePoint == null || servicePointChanged) {
                    servicePoint = ServicePointManager.FindServicePoint(host, port);
                    // servicePoint is now correct for current host and port 
                    servicePointChanged = false;
                } 
                return servicePoint; 
            }
        } 

        public SmtpDeliveryMethod DeliveryMethod {
            get {
                return deliveryMethod; 
            }
            set { 
                deliveryMethod = value; 
            }
        } 


        public string PickupDirectoryLocation {
            [ResourceExposure(ResourceScope.Machine)] 
            [ResourceConsumption(ResourceScope.Machine)]
            get { 
                return pickupDirectoryLocation; 
            }
            [ResourceExposure(ResourceScope.Machine)] 
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                pickupDirectoryLocation = value;
            } 
        }
        ///  
        ///    Set to true if we need SSL 
        /// 
        public bool EnableSsl { 
            get {
                return transport.EnableSsl;
            }
            set { 
                transport.EnableSsl = value;
            } 
        } 

        ///  
        /// Certificates used by the client for establishing an SSL connection with the server.
        /// 
        public X509CertificateCollection ClientCertificates {
            get { 
                return transport.ClientCertificates;
            } 
        } 

        public string TargetName { 
            set { this.targetName = value; }
            get { return this.targetName; }
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        internal MailWriter GetFileMailWriter(string pickupDirectory) 
        {
            if (Logging.On) Logging.PrintInfo(Logging.Web, "SmtpClient.Send() pickupDirectory=" + pickupDirectory); 
            if (!Path.IsPathRooted(pickupDirectory))
                throw new SmtpException(SR.GetString(SR.SmtpNeedAbsolutePickupDirectory));
            string filename;
            string pathAndFilename; 
            while (true) {
                filename = Guid.NewGuid().ToString() + ".eml"; 
                pathAndFilename = Path.Combine(pickupDirectory, filename); 
                if (!File.Exists(pathAndFilename))
                    break; 
            }

            FileStream fileStream = new FileStream(pathAndFilename, FileMode.CreateNew);
            return new MailWriter(fileStream); 
        }
 
        protected void OnSendCompleted(AsyncCompletedEventArgs e) 
        {
            if (SendCompleted != null) { 
                SendCompleted(this, e);
            }
        }
 
        void SendCompletedWaitCallback(object operationState) {
            OnSendCompleted((AsyncCompletedEventArgs)operationState); 
        } 

 
        public void Send(string from, string recipients, string subject, string body) {
            if (disposed) {
                throw new ObjectDisposedException(this.GetType().FullName);
            } 
            //validation happends in MailMessage constructor
            MailMessage mailMessage = new MailMessage(from, recipients, subject, body); 
            Send(mailMessage); 
        }
 

        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        public void Send(MailMessage message) { 
            if (Logging.On) Logging.Enter(Logging.Web, this, "Send", message);
            if (disposed) { 
                throw new ObjectDisposedException(this.GetType().FullName); 
            }
            try { 
                if (Logging.On) Logging.PrintInfo(Logging.Web, this, "Send", "DeliveryMethod=" + DeliveryMethod.ToString());
                if (Logging.On) Logging.Associate(Logging.Web, this, message);
                SmtpFailedRecipientException recipientException = null;
 
                if (InCall) {
                    throw new InvalidOperationException(SR.GetString(SR.net_inasync)); 
                } 

                if (message == null) { 
                    throw new ArgumentNullException("message");
                }

                if (DeliveryMethod == SmtpDeliveryMethod.Network) 
                    CheckHostAndPort();
 
                MailAddressCollection recipients = new MailAddressCollection(); 

                if (message.From == null) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpFromRequired));
                }

                if (message.To != null) { 
                    foreach (MailAddress address in message.To) {
                        recipients.Add(address); 
                    } 
                }
                if (message.Bcc != null) { 
                    foreach (MailAddress address in message.Bcc) {
                        recipients.Add(address);
                    }
                } 
                if (message.CC != null) {
                    foreach (MailAddress address in message.CC) { 
                        recipients.Add(address); 
                    }
                } 

                if (recipients.Count == 0) {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpRecipientRequired));
                } 

                transport.IdentityRequired = false;  // everything completes on the same thread. 
 
                try {
                    InCall = true; 
                    timedOut = false;
                    timer = new Timer(new TimerCallback(this.TimeOutCallback), null, Timeout, Timeout);

                    MailWriter writer; 
                    switch (DeliveryMethod) {
                        case SmtpDeliveryMethod.SpecifiedPickupDirectory: 
                            if (EnableSsl) 
                                throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl));
                            writer = GetFileMailWriter(PickupDirectoryLocation); 
                            break;
#if !FEATURE_PAL
                        case SmtpDeliveryMethod.PickupDirectoryFromIis:
                            if (EnableSsl) 
                                throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl));
                            writer = GetFileMailWriter(IisPickupDirectory.GetPickupDirectory()); 
                            break; 
#endif // !FEATURE_PAL
                        case SmtpDeliveryMethod.Network: 
                        default:
                            GetConnection();
                            writer = transport.SendMail(message.Sender != null ? message.Sender : message.From, recipients, message.BuildDeliveryStatusNotificationString(), out recipientException);
                            break; 
                    }
                    this.message = message; 
                    message.Send(writer, DeliveryMethod != SmtpDeliveryMethod.Network); 
                    writer.Close();
                    transport.ReleaseConnection(); 

                    //throw if we couldn't send to any of the recipients
                    if (DeliveryMethod == SmtpDeliveryMethod.Network)
                        if (recipientException != null) 
                            throw recipientException;
                } 
                catch (Exception e) { 

                    if (Logging.On) Logging.Exception(Logging.Web, this, "Send", e); 


                    if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) {
                        throw; 
                    }
 
 
                    Abort();
                    if (timedOut) { 
                        throw new SmtpException(SR.GetString(SR.net_timeout));
                    }

                    if (e is SecurityException || 
                        e is AuthenticationException ||
                        e is SmtpException) 
                    { 
                        throw;
                    } 

                    throw new SmtpException(SR.GetString(SR.SmtpSendMailFailure), e);
                }
                finally { 
                    InCall = false;
                    if (timer != null) { 
                        timer.Dispose(); 
                    }
                } 
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, this, "Send", null);
            }
        } 

 
 
        [HostProtection(ExternalThreading = true)]
        public void SendAsync(string from, string recipients, string subject, string body, object userToken) { 
            if (disposed) {
                throw new ObjectDisposedException(this.GetType().FullName);
            }
            SendAsync(new MailMessage(from, recipients, subject, body), userToken); 
        }
 
 
        [HostProtection(ExternalThreading = true)]
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        public void SendAsync(MailMessage message, object userToken) {
            if (disposed) {
                throw new ObjectDisposedException(this.GetType().FullName); 
            }
            if (Logging.On) Logging.Enter(Logging.Web, this, "SendAsync", "DeliveryMethod=" + DeliveryMethod.ToString()); 
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync Transport#" + ValidationHelper.HashString(transport)); 
            try {
                if (InCall) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_inasync));
                }

                if (message == null) { 
                    throw new ArgumentNullException("message");
                } 
 
                if (DeliveryMethod == SmtpDeliveryMethod.Network)
                    CheckHostAndPort(); 

                recipients = new MailAddressCollection();

                if (message.From == null) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpFromRequired));
                } 
 
                if (message.To != null) {
                    foreach (MailAddress address in message.To) { 
                        recipients.Add(address);
                    }
                }
                if (message.Bcc != null) { 
                    foreach (MailAddress address in message.Bcc) {
                        recipients.Add(address); 
                    } 
                }
                if (message.CC != null) { 
                    foreach (MailAddress address in message.CC) {
                        recipients.Add(address);
                    }
                } 

                if (recipients.Count == 0) { 
                    throw new InvalidOperationException(SR.GetString(SR.SmtpRecipientRequired)); 
                }
 
                try {
                    InCall = true;
                    cancelled = false;
                    this.message = message; 

#if !FEATURE_PAL 
                    CredentialCache cache; 
                    // Skip token capturing if no credentials are used or they don't include a default one.
                    // Also do capture the token if ICredential is not of CredentialCache type so we don't know what the exact credential response will be. 
                    transport.IdentityRequired = Credentials != null && ComNetOS.IsWinNt && (Credentials is SystemNetworkCredential || (cache = Credentials as CredentialCache) == null || cache.IsDefaultInCache);
#endif // !FEATURE_PAL

                    asyncOp = AsyncOperationManager.CreateOperation(userToken); 
                    switch (DeliveryMethod) {
                        case SmtpDeliveryMethod.SpecifiedPickupDirectory: 
                            { 
                                if (EnableSsl)
                                    throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl)); 
                                writer = GetFileMailWriter(PickupDirectoryLocation);
                                message.Send(writer, DeliveryMethod != SmtpDeliveryMethod.Network);

                                if (writer != null) 
                                    writer.Close();
 
                                transport.ReleaseConnection(); 
                                AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, asyncOp.UserSuppliedState);
                                InCall = false; 
                                asyncOp.PostOperationCompleted(onSendCompletedDelegate, eventArgs);
                                break;
                            }
#if !FEATURE_PAL 
                        case SmtpDeliveryMethod.PickupDirectoryFromIis:
                            { 
                                if (EnableSsl) 
                                    throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl));
                                writer = GetFileMailWriter(IisPickupDirectory.GetPickupDirectory()); 
                                message.Send(writer, DeliveryMethod != SmtpDeliveryMethod.Network);

                                if (writer != null)
                                    writer.Close(); 

                                transport.ReleaseConnection(); 
                                AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, asyncOp.UserSuppliedState); 
                                InCall = false;
                                asyncOp.PostOperationCompleted(onSendCompletedDelegate, eventArgs); 
                                break;
                            }
#endif // !FEATURE_PAL
 
                        case SmtpDeliveryMethod.Network:
                        default: 
                            operationCompletedResult = new ContextAwareResult(transport.IdentityRequired, true, null, this, _ContextSafeCompleteCallback); 
                            lock (operationCompletedResult.StartPostingAsyncOp())
                            { 
                                GlobalLog.Print("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync calling BeginConnect.  Transport#" + ValidationHelper.HashString(transport));
                                transport.BeginGetConnection(ServicePoint, operationCompletedResult, ConnectCallback, operationCompletedResult);
                                operationCompletedResult.FinishPostingAsyncOp();
                            } 
                            break;
                    } 
 
                }
                catch (Exception e) { 
                    InCall = false;

                    if (Logging.On) Logging.Exception(Logging.Web, this, "Send", e);
 
                    if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) {
                        throw; 
                    } 

                    Abort(); 
                    if (timedOut) {
                        throw new SmtpException(SR.GetString(SR.net_timeout));
                    }
 
                    if (e is SecurityException ||
                        e is AuthenticationException || 
                        e is SmtpException) 
                    {
                        throw; 
                    }

                    throw new SmtpException(SR.GetString(SR.SmtpSendMailFailure), e);
                } 
            } finally {
                if (Logging.On) Logging.Exit(Logging.Web, this, "SendAsync", null); 
                GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync"); 
            }
        } 


        public void SendAsyncCancel() {
            if (disposed) { 
                throw new ObjectDisposedException(this.GetType().FullName);
            } 
            if (Logging.On) Logging.Enter(Logging.Web, this, "SendAsyncCancel", null); 
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel");
            try { 
                if (!InCall || cancelled) {
                    return;
                }
 
                cancelled = true;
                Abort(); 
            } finally { 
                if (Logging.On) Logging.Exit(Logging.Web, this, "SendAsyncCancel", null);
                GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel"); 
            }
        }

 
        //*********************************
        // private methods 
        //******************************** 
        internal bool InCall {
            get { 
                return inCall;
            }
            set {
                inCall = value; 
            }
        } 
 
        internal static MailSettingsSectionGroupInternal MailConfiguration {
            get { 
                if (mailConfiguration == null) {
                    mailConfiguration = MailSettingsSectionGroupInternal.GetSection();
                }
                return mailConfiguration; 
            }
        } 
 

        void CheckHostAndPort() { 

            if (host == null || host.Length == 0) {
                throw new InvalidOperationException(SR.GetString(SR.UnspecifiedHost));
            } 
            if (port <= 0 || port > maxPortValue) {
                throw new InvalidOperationException(SR.GetString(SR.InvalidPort)); 
            } 
        }
 

        void TimeOutCallback(object state) {
            if (!timedOut) {
                timedOut = true; 
                Abort();
            } 
        } 

 
        void Complete(Exception exception, IAsyncResult result) {
            ContextAwareResult operationCompletedResult = (ContextAwareResult)result.AsyncState;
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete");
            try { 
                if (cancelled) {
                    //any exceptions were probably caused by cancellation, clear it. 
                    exception = null; 
                    Abort();
                } 
                // A failed recipient exception is benign
                else if (exception != null && (!(exception is SmtpFailedRecipientException) || ((SmtpFailedRecipientException)exception).fatal))
                {
                    GlobalLog.Print("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete Exception: " + exception.ToString()); 
                    Abort();
 
                    if (!(exception is SmtpException)) { 
                        exception = new SmtpException(SR.GetString(SR.SmtpSendMailFailure), exception);
                    } 
                }
                else {
                    if (writer != null) {
                        writer.Close(); 
                    }
                    transport.ReleaseConnection(); 
                } 
            }
            finally { 
                operationCompletedResult.InvokeCallback(exception);
            }
            GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete");
        } 

        static void ContextSafeCompleteCallback(IAsyncResult ar) 
        { 
            ContextAwareResult result = (ContextAwareResult)ar;
            SmtpClient client = (SmtpClient)ar.AsyncState; 
            Exception exception = result.Result as Exception;
            AsyncOperation asyncOp = client.asyncOp;
            AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(exception, client.cancelled, asyncOp.UserSuppliedState);
            client.InCall = false; 
            asyncOp.PostOperationCompleted(client.onSendCompletedDelegate, eventArgs);
        } 
 
        /*
          void DisconnectCallback(IAsyncResult result) { 
              SmtpClient client = (SmtpClient)result.AsyncState;

              try {
                  client.transport.EndDisconnect(result); 
              }
              catch (Exception e) { 
                  Complete(e); 
                  return;
              } 
              Complete(null);
          }
                */
 
        void SendMessageCallback(IAsyncResult result) {
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback"); 
            try { 
                message.EndSend(result);
                Complete(null, result); 
            }
            catch (Exception e) {
                Complete(e, result);
            } 
            GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback");
        } 
 

        void SendMailCallback(IAsyncResult result) { 
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
            try {
                writer = transport.EndSendMail(result);
            } 
            catch (Exception e)
            { 
                // Note the difference between the singular and plural FailedRecipient exceptions. 
                // Only fail immediately if we couldn't send to any recipients.
                if (!(e is SmtpFailedRecipientException) || ((SmtpFailedRecipientException)e).fatal) 
                {
                    Complete(e, result);
                    GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
                    return; 
                }
            } 
            try { 
                if (cancelled) {
                    Complete(null, result); 
                }
                else {
                    message.BeginSend(writer, DeliveryMethod != SmtpDeliveryMethod.Network, new AsyncCallback(SendMessageCallback), result.AsyncState);
                } 
            }
            catch (Exception e) { 
                Complete(e, result); 
            }
            GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback"); 
        }


        void ConnectCallback(IAsyncResult result) { 
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::ConnectCallback");
            try { 
                transport.EndGetConnection(result); 
                if (cancelled) {
                    Complete(null, result); 
                }
                else {
                    transport.BeginSendMail(message.Sender != null ? message.Sender : message.From, recipients, message.BuildDeliveryStatusNotificationString(), new AsyncCallback(SendMailCallback), result.AsyncState);
                } 
            }
            catch (Exception e) { 
                Complete(e, result); 
            }
            GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::ConnectCallback"); 
        }


        void GetConnection() { 
            if (!transport.IsConnected) {
                transport.GetConnection(ServicePoint); 
            } 
        }
 

        void Abort() {
            try {
                transport.Abort(); 
            }
            catch { 
            } 
        }
 
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        } 

        protected virtual void Dispose(bool disposing) { 
            if (disposing && !disposed ) { 
                if (InCall && !cancelled) {
                    cancelled = true; 
                    Abort();
                }

                if (transport != null) { 
                    transport.CloseIdleConnections(ServicePoint);
                } 
 
                if (timer != null) {
                    timer.Dispose(); 
                }

                disposed = true;
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK