SmtpTransport.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net.Mail 
{ 
    using System;
    using System.Collections; 
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Net.Sockets; 
    using System.Text;
    using System.Net.Security; 
    using System.Security.Cryptography.X509Certificates; 
    using System.Net.Mime;
    using System.Security.Principal; 
    using System.Security.Permissions;
    using System.Threading;
    using System.Diagnostics;
 
    internal enum SupportedAuth{
        None = 0, Login = 1, 
#if !FEATURE_PAL 
        NTLM = 2, GSSAPI = 4, WDigest = 8
#endif 
    };

    internal class SmtpPooledStream:PooledStream{
        internal bool previouslyUsed; 
        internal bool dsnEnabled;  //delivery  status notification
        internal ICredentialsByHost creds; 
        internal SmtpPooledStream(ConnectionPool connectionPool, TimeSpan lifetime, bool checkLifetime) : base (connectionPool,lifetime,checkLifetime) { 
        }
 
        // maximum line length in SMTP response is 76 so this is a bit more conservative
        const int safeBufferLength = 80;

        // Cleans up an open connection to an SMTP server by sending the QUIT 
        // response, reading the server's response, and disposing the base stream
        protected override void Dispose(bool disposing) 
        { 
            if (Logging.On) {
                Logging.Enter(Logging.Web, "SmtpPooledStream::Dispose #" + ValidationHelper.HashString(this)); 
            }
            if (disposing) {
                if (this.NetworkStream.Connected) {
                    this.Write(SmtpCommands.Quit, 0, SmtpCommands.Quit.Length); 
                    this.Flush();
 
                    // read the response - this is a formality since the connection is shut down 
                    // immediately by the server so this data can safely be ignored but buffer
                    // must be read to ensure a FIN is sent instead of a RST 
                    byte[] buffer = new byte[safeBufferLength];
                    int result = this.Read(buffer, 0, safeBufferLength);
                }
            } 
            base.Dispose(disposing);
            if (Logging.On) { 
                Logging.Exit(Logging.Web, "SmtpPooledStream::Dispose #" + ValidationHelper.HashString(this)); 
            }
        } 
    }

    internal class SmtpTransport
    { 
        internal const int DefaultPort = 25;
 
        ISmtpAuthenticationModule[] authenticationModules; 
        SmtpConnection connection;
        SmtpClient client; 
        ICredentialsByHost credentials;
        int timeout = 100000; // seconds
        ArrayList failedRecipientExceptions = new ArrayList();
        bool m_IdentityRequired; 

        bool enableSsl = false; 
        X509CertificateCollection clientCertificates = null; 

        ServicePoint lastUsedServicePoint; 

        internal SmtpTransport(SmtpClient client) : this(client, SmtpAuthenticationManager.GetModules()) {
        }
 

        internal SmtpTransport(SmtpClient client, ISmtpAuthenticationModule[] authenticationModules) 
        { 
            this.client = client;
 
            if (authenticationModules == null)
            {
                throw new ArgumentNullException("authenticationModules");
            } 

            this.authenticationModules = authenticationModules; 
        } 

        internal ICredentialsByHost Credentials 
        {
            get
            {
                return credentials; 
            }
            set 
            { 
                credentials = value;
            } 
        }

        internal bool IdentityRequired
        { 
            get
            { 
                return m_IdentityRequired; 
            }
 
            set
            {
                m_IdentityRequired = value;
            } 
        }
 
        internal bool IsConnected 
        {
            get 
            {
                return connection != null && connection.IsConnected;
            }
        } 

        internal int Timeout 
        { 
            get
            { 
                return timeout;
            }
            set
            { 
                if (value < 0)
                { 
                    throw new ArgumentOutOfRangeException("value"); 
                }
 
                timeout = value;
            }
        }
 
        internal bool EnableSsl
        { 
            get 
            {
                return enableSsl; 
            }
            set
            {
#if !FEATURE_PAL 
                enableSsl = value;
#else 
                throw new NotImplementedException("ROTORTODO"); 
#endif
            } 
        }

        internal X509CertificateCollection ClientCertificates
        { 
            get {
                if (clientCertificates == null) { 
                    clientCertificates = new X509CertificateCollection(); 
                }
                return clientCertificates; 
            }
        }

        // check to see if we're using a different servicepoint than the last 
        // servicepoint used to get a connectionpool
        // 
        // preconditions: servicePoint must have valid host and port (checked in SmtpClient) 
        //
        // postconditions: if servicePoint is different than the last servicePoint used by this object, 
        // the connection pool for the previous servicepoint will be cleaned up and servicePoint will be
        // cached to identify if it has changed in future uses of this SmtpTransport object
        private void UpdateServicePoint(ServicePoint servicePoint)
        { 
            if (lastUsedServicePoint == null) {
                lastUsedServicePoint = servicePoint; 
            } 
            else if (lastUsedServicePoint.Host != servicePoint.Host
               || lastUsedServicePoint.Port != servicePoint.Port) { 
                ConnectionPoolManager.CleanupConnectionPool(servicePoint, "");
                lastUsedServicePoint = servicePoint;
            }
        } 

        internal void GetConnection(ServicePoint servicePoint) 
        { 
            try {
                Debug.Assert(servicePoint != null, "no ServicePoint provided by SmtpClient"); 
                // check to see if we have a different connection than last time
                UpdateServicePoint(servicePoint);
                connection = new SmtpConnection(this, client, credentials, authenticationModules);
                connection.Timeout = timeout; 
                if(Logging.On)Logging.Associate(Logging.Web, this, connection);
 
                if (EnableSsl) 
                {
                    connection.EnableSsl = true; 
                    connection.ClientCertificates = ClientCertificates;
                }
                connection.GetConnection(servicePoint);
            } 
            finally {
 
            } 
        }
 

        internal IAsyncResult BeginGetConnection(ServicePoint servicePoint, ContextAwareResult outerResult, AsyncCallback callback, object state)
        {
            GlobalLog.Enter("SmtpTransport#" + ValidationHelper.HashString(this) + "::BeginConnect"); 
            IAsyncResult result = null;
            try{ 
                UpdateServicePoint(servicePoint); 
                connection = new SmtpConnection(this, client, credentials, authenticationModules);
                connection.Timeout = timeout; 
                if(Logging.On)Logging.Associate(Logging.Web, this, connection);
                if (EnableSsl)
                {
                    connection.EnableSsl = true; 
                    connection.ClientCertificates = ClientCertificates;
                } 
 
                result = connection.BeginGetConnection(servicePoint, outerResult, callback, state);
            } 
            catch(Exception innerException){
                throw new SmtpException(SR.GetString(SR.MailHostNotFound), innerException);
            }
            GlobalLog.Leave("SmtpTransport#" + ValidationHelper.HashString(this) + "::BeginConnect [....] Completion"); 
            return result;
        } 
 

        internal void EndGetConnection(IAsyncResult result) 
        {
            GlobalLog.Enter("SmtpTransport#" + ValidationHelper.HashString(this) + "::EndGetConnection");
            try {
                connection.EndGetConnection(result); 
            }
            finally { 
 
                GlobalLog.Leave("SmtpTransport#" + ValidationHelper.HashString(this) + "::EndConnect");
            } 
        }


        internal IAsyncResult BeginSendMail(MailAddress sender, MailAddressCollection recipients, string deliveryNotify, AsyncCallback callback, object state) 
        {
            if (sender == null) 
            { 
                throw new ArgumentNullException("sender");
            } 

            if (recipients == null)
            {
                throw new ArgumentNullException("recipients"); 
            }
 
            GlobalLog.Assert(recipients.Count > 0, "SmtpTransport::BeginSendMail()|recepients.Count <= 0"); 

            SendMailAsyncResult result = new SendMailAsyncResult(connection, sender.SmtpAddress, recipients, connection.DSNEnabled?deliveryNotify:null, callback, state); 
            result.Send();
            return result;
        }
 

        internal void ReleaseConnection() { 
            if(connection != null){ 
                connection.ReleaseConnection();
            } 
        }

        internal void Abort() {
            if(connection != null){ 
                connection.Abort();
            } 
        } 

 
        internal MailWriter EndSendMail(IAsyncResult result)
        {
            try {
                return SendMailAsyncResult.End(result); 
            }
            finally { 
 
            }
        } 

        internal MailWriter SendMail(MailAddress sender, MailAddressCollection recipients, string deliveryNotify, out SmtpFailedRecipientException exception)
        {
            if (sender == null) 
            {
                throw new ArgumentNullException("sender"); 
            } 

            if (recipients == null) 
            {
                throw new ArgumentNullException("recipients");
            }
 
            GlobalLog.Assert(recipients.Count > 0, "SmtpTransport::SendMail()|recepients.Count <= 0");
 
            MailCommand.Send(connection, SmtpCommands.Mail, sender.SmtpAddress); 
            failedRecipientExceptions.Clear();
 
            exception = null;
            string response;
            foreach (MailAddress address in recipients) {
                if (!RecipientCommand.Send(connection, connection.DSNEnabled?address.SmtpAddress + deliveryNotify:address.SmtpAddress, out response)) { 
                    failedRecipientExceptions.Add(new SmtpFailedRecipientException(connection.Reader.StatusCode, address.SmtpAddress, response));
                } 
            } 

            if (failedRecipientExceptions.Count > 0) 
            {
                if (failedRecipientExceptions.Count == 1)
                {
                    exception = (SmtpFailedRecipientException) failedRecipientExceptions[0]; 
                }
                else 
                { 
                    exception = new SmtpFailedRecipientsException(failedRecipientExceptions, failedRecipientExceptions.Count == recipients.Count);
                } 

                if (failedRecipientExceptions.Count == recipients.Count){
                    exception.fatal = true;
                    throw exception; 
                }
            } 
 
            DataCommand.Send(connection);
            return new MailWriter(connection.GetClosableStream()); 
        }

        internal void CloseIdleConnections(ServicePoint servicePoint)
        { 
            ConnectionPoolManager.CleanupConnectionPool(servicePoint, "");
        } 
    } 

 
    class SendMailAsyncResult : LazyAsyncResult
    {
        SmtpConnection connection;
        string from; 
        string deliveryNotify;
        static AsyncCallback sendMailFromCompleted = new AsyncCallback(SendMailFromCompleted); 
        static AsyncCallback sendToCompleted = new AsyncCallback(SendToCompleted); 
        static AsyncCallback sendToCollectionCompleted = new AsyncCallback(SendToCollectionCompleted);
        static AsyncCallback sendDataCompleted = new AsyncCallback(SendDataCompleted); 
        ArrayList failedRecipientExceptions = new ArrayList();
        Stream stream;
        string to;
        MailAddressCollection toCollection; 
        int toIndex;
 
 
        internal SendMailAsyncResult(SmtpConnection connection, string from, MailAddressCollection toCollection, string deliveryNotify, AsyncCallback callback, object state) : base(null, state, callback)
        { 
            this.toCollection = toCollection;
            this.connection = connection;
            this.from = from;
            this.deliveryNotify = deliveryNotify; 
        }
 
        internal void Send(){ 
            SendMailFrom();
        } 

        internal static MailWriter End(IAsyncResult result)
        {
            SendMailAsyncResult thisPtr = (SendMailAsyncResult)result; 
            object sendMailResult = thisPtr.InternalWaitForCompletion();
            if (sendMailResult is Exception) 
                throw (Exception)sendMailResult; 
            return new MailWriter(thisPtr.stream);
        } 
        void SendMailFrom()
        {
            IAsyncResult result = MailCommand.BeginSend(connection, SmtpCommands.Mail, from, sendMailFromCompleted, this);
            if (!result.CompletedSynchronously) 
            {
                return; 
            } 

            MailCommand.EndSend(result); 
            SendTo();
        }

        static void SendMailFromCompleted(IAsyncResult result) 
        {
            if (!result.CompletedSynchronously) 
            { 
                SendMailAsyncResult thisPtr = (SendMailAsyncResult)result.AsyncState;
                try 
                {
                    MailCommand.EndSend(result);
                    thisPtr.SendTo();
                } 
                catch (Exception e)
                { 
                    thisPtr.InvokeCallback(e); 
                }
            } 
        }

        void SendTo()
        { 
            GlobalLog.Enter("SendMailAsyncResult#" + ValidationHelper.HashString(this) + "::SendTo");
            if (to != null) 
            { 
                GlobalLog.Print("SendMailAsyncResult#" + ValidationHelper.HashString(this) + "::SendTo - to string");
                IAsyncResult result = RecipientCommand.BeginSend(connection, (deliveryNotify!=null)?to + deliveryNotify:to, sendToCompleted, this); 
                if (!result.CompletedSynchronously)
                {
                    return;
                } 
                string response;
                if (!RecipientCommand.EndSend(result, out response)) 
                { 
                    throw new SmtpFailedRecipientException(connection.Reader.StatusCode, to, response);
                } 
                SendData();
            }

            else 
            {
                GlobalLog.Print("SendMailAsyncResult#" + ValidationHelper.HashString(this) + "::SendTo - to collection"); 
                if (SendToCollection()) 
                {
                    SendData(); 
                }
            }

            GlobalLog.Leave("SendMailAsyncResult#" + ValidationHelper.HashString(this) + "::SendTo"); 
        }
 
        static void SendToCompleted(IAsyncResult result) 
        {
            if (!result.CompletedSynchronously) 
            {
                SendMailAsyncResult thisPtr = (SendMailAsyncResult)result.AsyncState;
                try
                { 
                    string response;
                    if (RecipientCommand.EndSend(result, out response)) 
                    { 
                        thisPtr.SendData();
                    } 
                    else
                    {
                        thisPtr.InvokeCallback(new SmtpFailedRecipientException(thisPtr.connection.Reader.StatusCode, thisPtr.to, response));
                    } 
                }
                catch (Exception e) 
                { 
                    thisPtr.InvokeCallback(e);
                } 
            }
        }

        bool SendToCollection() 
        {
            while (toIndex < toCollection.Count) 
            { 
                MultiAsyncResult result = (MultiAsyncResult)RecipientCommand.BeginSend(connection, toCollection[toIndex++].SmtpAddress + deliveryNotify, sendToCollectionCompleted, this);
                if (!result.CompletedSynchronously) 
                {
                    return false;
                }
                string response; 
                if (!RecipientCommand.EndSend(result, out response)){
                    failedRecipientExceptions.Add(new SmtpFailedRecipientException(connection.Reader.StatusCode, toCollection[toIndex - 1].SmtpAddress, response)); 
                } 
            }
            return true; 
        }

        static void SendToCollectionCompleted(IAsyncResult result)
        { 
            if (!result.CompletedSynchronously)
            { 
                SendMailAsyncResult thisPtr = (SendMailAsyncResult)result.AsyncState; 
                try
                { 
                    string response;
                    if (!RecipientCommand.EndSend(result, out response))
                    {
                        thisPtr.failedRecipientExceptions.Add(new SmtpFailedRecipientException(thisPtr.connection.Reader.StatusCode, thisPtr.toCollection[thisPtr.toIndex - 1].SmtpAddress, response)); 

                        if (thisPtr.failedRecipientExceptions.Count == thisPtr.toCollection.Count) 
                        { 
                            SmtpFailedRecipientException exception = null;
                            if (thisPtr.toCollection.Count == 1) 
                            {
                                exception = (SmtpFailedRecipientException)thisPtr.failedRecipientExceptions[0];
                            }
                            else 
                            {
                                exception = new SmtpFailedRecipientsException(thisPtr.failedRecipientExceptions, true); 
                            } 
                            exception.fatal = true;
                            thisPtr.InvokeCallback(exception); 
                            return;
                        }
                    }
                    if (thisPtr.SendToCollection()) 
                    {
                        thisPtr.SendData(); 
                    } 
                }
                catch (Exception e) 
                {
                    thisPtr.InvokeCallback(e);
                }
            } 
        }
 
        void SendData() 
        {
            IAsyncResult result = DataCommand.BeginSend(connection, sendDataCompleted, this); 
            if (!result.CompletedSynchronously)
            {
                return;
            } 
            DataCommand.EndSend(result);
            stream = connection.GetClosableStream(); 
            if (failedRecipientExceptions.Count > 1) 
            {
                InvokeCallback(new SmtpFailedRecipientsException(failedRecipientExceptions, failedRecipientExceptions.Count == toCollection.Count)); 
            }
            else if (failedRecipientExceptions.Count == 1)
            {
                InvokeCallback(failedRecipientExceptions[0]); 
            }
            else 
            { 
                InvokeCallback();
            } 
        }

        static void SendDataCompleted(IAsyncResult result)
        { 
            if (!result.CompletedSynchronously)
            { 
                SendMailAsyncResult thisPtr = (SendMailAsyncResult)result.AsyncState; 
                try
                { 
                    DataCommand.EndSend(result);
                    thisPtr.stream = thisPtr.connection.GetClosableStream();
                    if (thisPtr.failedRecipientExceptions.Count > 1)
                    { 
                        thisPtr.InvokeCallback(new SmtpFailedRecipientsException(thisPtr.failedRecipientExceptions, thisPtr.failedRecipientExceptions.Count == thisPtr.toCollection.Count));
                    } 
                    else if (thisPtr.failedRecipientExceptions.Count == 1) 
                    {
                        thisPtr.InvokeCallback(thisPtr.failedRecipientExceptions[0]); 
                    }
                    else
                    {
                        thisPtr.InvokeCallback(); 
                    }
                } 
                catch (Exception e) 
                {
                    thisPtr.InvokeCallback(e); 
                }
            }
        }
    } 
 }

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

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