Ejemplo n.º 1
0
        /// <summary>
        /// Enqueue the SmtpOutboundClient for use by another message.
        /// </summary>
        /// <param name="client">The client to queue.</param>
        public void Enqueue(SmtpOutboundClient client)
        {
            SmtpClientMxRecords mxConnections = this._OutboundConnections.GetOrAdd(client.SmtpStream.LocalAddress.ToString(), new SmtpClientMxRecords());
            SmtpClientQueue     clientQueue   = null;

            lock (this._ClientPoolLock)
            {
                if (!mxConnections.TryGetValue(client.MXRecord.Host, out clientQueue))
                {
                    clientQueue = new SmtpClientQueue();
                    if (!mxConnections.TryAdd(client.MXRecord.Host, clientQueue))
                    {
                        throw new Exception("Failed to add new SmtpClientQueue");
                    }
                }
            }
            clientQueue.Enqueue(client);
            try
            {
                clientQueue.InUseConnections.Remove(client);
            }
            catch (Exception)
            {
                // Already removed.
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Attempts to get a SmtpClient using the outbound IP address and the specified MX records collection.
        ///
        /// WARNING: returned SmtpOutboundClient will have it's IsActive flag set to true make sure to set it to
        ///		     false when done with it or it will never be removed by the idle timeout.
        /// </summary>
        /// <param name="ipAddress">The local outbound endpoint we wan't to use.</param>
        /// <param name="mxs">The MX records for the domain we wan't a client to connect to.</param>
        /// <returns>Tuple containing a DequeueAsyncResult and either an SmtpOutboundClient or Null if failed to dequeue.</returns>
        public async Task <SmtpOutboundClientDequeueResponse> DequeueAsync(VirtualMTA ipAddress, MXRecord[] mxs)
        {
            // If there aren't any remote mx records then we can't send
            if (mxs.Length < 1)
            {
                return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.NoMxRecords));
            }

            SmtpClientMxRecords mxConnections = this._OutboundConnections.GetOrAdd(ipAddress.IPAddress.ToString(), new SmtpClientMxRecords());
            SmtpOutboundClient  smtpClient    = null;

            // Check that we aren't being throttled.
            if (!ThrottleManager.Instance.TryGetSendAuth(ipAddress, mxs[0]))
            {
                return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.Throttled));
            }

            // Loop through all the MX Records.
            for (int i = 0; i < mxs.Length; i++)
            {
                try
                {
                    // To prevent us bombarding a server that is blocking us we will check the service not available manager
                    // to see if we can send to this MX, Max 1 message/minute, if we can't we won't.
                    // At the moment we stop to all MXs for a domain if one of them responds with service unavailable.
                    // This could be improved to allow others to continue, we should however if blocked on all MX's with
                    // lowest preference  not move on to the others.
                    if (ServiceNotAvailableManager.IsServiceUnavailable(ipAddress.IPAddress.ToString(), mxs[i].Host))
                    {
                        return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.ServiceUnavalible));
                    }

                    SmtpClientQueue clientQueue = null;
                    lock (this._ClientPoolLock)
                    {
                        if (!mxConnections.TryGetValue(mxs[i].Host, out clientQueue))
                        {
                            clientQueue = new SmtpClientQueue();
                            if (!mxConnections.TryAdd(mxs[i].Host, clientQueue))
                            {
                                return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.FailedToAddToSmtpClientQueue));
                            }
                        }
                    }
                    // Loop through the client queue and make sure we get one thats still connected.
                    // They may have idled out while waiting.
                    while (!clientQueue.IsEmpty)
                    {
                        if (clientQueue.TryDequeue(out smtpClient))
                        {
                            if (smtpClient.Connected)
                            {
                                clientQueue.InUseConnections.Add(smtpClient);
                                smtpClient.LastActive = DateTime.UtcNow;
                                smtpClient.IsActive   = true;
                                return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.Success, smtpClient));
                            }
                        }
                    }

                    // Nothing was in the queue or all queued items timed out.
                    CreateNewConnectionAsyncResult createNewConnectionResult = await clientQueue.CreateNewConnectionAsync(ipAddress, mxs[i]);

                    if (createNewConnectionResult.Exception == null)
                    {
                        return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.Success, createNewConnectionResult.OutboundClient));
                    }
                    else if (createNewConnectionResult.Exception is MaxConnectionsException)
                    {
                        return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.FailedMaxConnections));
                    }
                    else
                    {
                        throw createNewConnectionResult.Exception;
                    }
                }
                catch (SocketException ex)
                {
                    // We have failed to connect to the remote host.
                    Logging.Warn("Failed to connect to " + mxs[i].Host, ex);

                    // If we fail to connect to an MX then don't try again for at least a minute.
                    ServiceNotAvailableManager.Add(ipAddress.IPAddress.ToString(), mxs[i].Host, DateTime.UtcNow);

                    // Failed to connect to MX
                    if (i == mxs.Length - 1)
                    {
                        return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.FailedToConnect));
                    }
                }
                catch (Exception ex)
                {
                    // Something unexpected and unhandled has happened, log it and return unknown.
                    Logging.Error("SmtpClientPool.DequeueAsync Unhandled Exception", ex);
                    return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.Unknown));
                }
            }

            // It we got here then we have failed to connect to the remote host.
            return(new SmtpOutboundClientDequeueResponse(SmtpOutboundClientDequeueAsyncResult.FailedToConnect));
        }