Example #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.
            }
        }
Example #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 (_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)
                {
                    // 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));
        }
Example #3
0
        private SmtpClientPool()
        {
            new Thread(new ThreadStart(delegate
            {
                while (true)
                {
                    try
                    {
                        IEnumerator <KeyValuePair <string, SmtpClientMxRecords> > enumMXs = this._OutboundConnections.GetEnumerator();
                        while (enumMXs.MoveNext())
                        {
                            int count   = 0;
                            int removed = 0;
                            KeyValuePair <string, SmtpClientMxRecords> current = enumMXs.Current;
                            SmtpClientMxRecords mxRecords = current.Value;
                            IEnumerator <KeyValuePair <string, SmtpClientQueue> > enumClients = mxRecords.GetEnumerator();
                            while (enumClients.MoveNext())
                            {
                                count++;
                                KeyValuePair <string, SmtpClientQueue> current2 = enumClients.Current;
                                SmtpClientQueue clients = current2.Value;
                                if (clients.Count == 0 && clients.InUseConnections.Count == 0)
                                {
                                    ConcurrentDictionary <string, SmtpClientQueue> arg_8B_0 = mxRecords;
                                    current2 = enumClients.Current;
                                    if (arg_8B_0.TryRemove(current2.Key, out clients))
                                    {
                                        //string arg_AF_0 = "Removed empty SMTP Clients Queue for ";
                                        //current2 = enumClients.Current;
                                        //Logging.Debug(arg_AF_0 + current2.Key);
                                        removed++;
                                    }
                                    else
                                    {
                                        string arg_D6_0 = "Failed to remove empty SMTP Clients Queue for ";
                                        current2        = enumClients.Current;
                                        Logging.Debug(arg_D6_0 + current2.Key);
                                    }
                                }
                            }

                            /*Logging.Debug(string.Concat(new string[]
                             *                          {
                             *                                  "SmtpClientPool : Removed ",
                             *                                  removed.ToString("N0"),
                             *                                  " client queues. ",
                             *                                  (count - removed).ToString("N0"),
                             *                                  " remaining."
                             *                          }));*/
                        }
                    }
                    catch (Exception ex)
                    {
                        Logging.Debug("SmtpClientPool: " + ex);
                    }
                    finally
                    {
                        Thread.Sleep(60000);
                    }
                }
            }))
            {
                IsBackground = true
            }.Start();
        }