예제 #1
0
        private async Task SendMessageAsync(MtaQueuedMessage msg)
        {
            // Check that the message next attempt after has passed.
            if (msg.AttemptSendAfterUtc > DateTime.UtcNow)
            {
                await RabbitMqOutboundQueueManager.Enqueue(msg);

                await Task.Delay(50);                 // To prevent a tight loop within a Task thread we should sleep here.

                return;
            }

            if (await Data.MtaTransaction.HasBeenHandledAsync(msg.ID))
            {
                msg.IsHandled = true;
                return;
            }

            // Get the send that this message belongs to so that we can check the send state.
            var snd = await SendManager.Instance.GetSendAsync(msg.InternalSendID);

            switch (snd.SendStatus)
            {
            // The send is being discarded so we should discard the message.
            case SendStatus.Discard:
                await MtaMessageHelper.HandleMessageDiscardAsync(msg);

                return;

            // The send is paused, the handle pause state will delay, without deferring, the message for a while so we can move on to other messages.
            case SendStatus.Paused:
                await MtaMessageHelper.HandleSendPaused(msg);

                return;

            // Send is active so we don't need to do anything.
            case SendStatus.Active:
                break;

            // Unknown send state, requeue the message and log error. Cannot send!
            default:
                msg.AttemptSendAfterUtc = DateTime.UtcNow.AddMinutes(1);
                await RabbitMqOutboundQueueManager.Enqueue(msg);

                Logging.Error("Failed to send message. Unknown SendStatus[" + snd.SendStatus + "]!");
                return;
            }

            // Check the message hasn't timed out. If it has don't attempt to send it.
            // Need to do this here as there may be a massive backlog on the server
            // causing messages to be waiting for ages after there AttemptSendAfter
            // before picking up. The MAX_TIME_IN_QUEUE should always be enforced.
            if (msg.AttemptSendAfterUtc - msg.QueuedTimestampUtc > new TimeSpan(0, MtaParameters.MtaMaxTimeInQueue, 0))
            {
                await MtaMessageHelper.HandleDeliveryFailAsync(msg, MtaParameters.TIMED_OUT_IN_QUEUE_MESSAGE, null, null);
            }
            else
            {
                MailAddress rcptTo    = new MailAddress(msg.RcptTo[0]);
                MailAddress mailFrom  = new MailAddress(msg.MailFrom);
                MXRecord[]  mXRecords = DNSManager.GetMXRecords(rcptTo.Host);
                // If mxs is null then there are no MX records.
                if (mXRecords == null || mXRecords.Length < 1)
                {
                    await MtaMessageHelper.HandleDeliveryFailAsync(msg, "550 Domain Not Found.", null, null);
                }
                else if (IsMxBlacklisted(mXRecords))
                {
                    await MtaMessageHelper.HandleDeliveryFailAsync(msg, "550 Domain blacklisted.", null, mXRecords[0]);
                }
                else
                {
                    var vMtaGroup  = VirtualMtaManager.GetVirtualMtaGroup(msg.VirtualMTAGroupID);
                    var sendResult = await MantaSmtpClientPoolCollection.Instance.SendAsync(mailFrom, rcptTo, vMtaGroup, mXRecords, msg.Message);

                    switch (sendResult.MantaOutboundClientResult)
                    {
                    case MantaOutboundClientResult.FailedToConnect:
                        await MtaMessageHelper.HandleFailedToConnectAsync(msg, sendResult.VirtualMTA, sendResult.MXRecord);

                        break;

                    case MantaOutboundClientResult.MaxConnections:
                        await RabbitMqOutboundQueueManager.Enqueue(msg);

                        break;

                    case MantaOutboundClientResult.MaxMessages:
                        await MtaMessageHelper.HandleDeliveryThrottleAsync(msg, sendResult.VirtualMTA, sendResult.MXRecord);

                        break;

                    case MantaOutboundClientResult.RejectedByRemoteServer:
                        if (string.IsNullOrWhiteSpace(sendResult.Message))
                        {
                            Logging.Error("RejectedByRemoteServer but no message!");
                            await MtaMessageHelper.HandleDeliveryDeferralAsync(msg, sendResult.Message, sendResult.VirtualMTA, sendResult.MXRecord);
                        }
                        if (sendResult.Message[0] == '4')
                        {
                            await MtaMessageHelper.HandleDeliveryDeferralAsync(msg, sendResult.Message, sendResult.VirtualMTA, sendResult.MXRecord);
                        }
                        else
                        {
                            await MtaMessageHelper.HandleDeliveryFailAsync(msg, sendResult.Message, sendResult.VirtualMTA, sendResult.MXRecord);
                        }
                        break;

                    case MantaOutboundClientResult.ServiceNotAvalible:
                        await MtaMessageHelper.HandleServiceUnavailableAsync(msg, sendResult.VirtualMTA);

                        break;

                    case MantaOutboundClientResult.Success:
                        await MtaMessageHelper.HandleDeliverySuccessAsync(msg, sendResult.VirtualMTA, sendResult.MXRecord, sendResult.Message);

                        break;

                    default:
                        // Something weird happening with this message, get it out of the way for a bit.
                        msg.AttemptSendAfterUtc = DateTime.UtcNow.AddMinutes(5);
                        await RabbitMqOutboundQueueManager.Enqueue(msg);

                        break;
                    }
                }
            }
        }