Exemple #1
0
        /// <summary>
        /// Creates a MantaEvent object and Fills it with the values from the data record.
        /// </summary>
        /// <param name="record">Record to get the data from.</param>
        /// <returns>MantaAubseEvent or MantaBounceEvent</returns>
        private static MantaEvent CreateAndFillMantaEventFromRecord(IDataRecord record)
        {
            MantaEventType type      = (MantaEventType)record.GetInt32("evn_type_id");
            MantaEvent     thisEvent = null;

            switch (type)
            {
            case MantaEventType.Abuse:
                thisEvent = new MantaAbuseEvent();
                break;

            case MantaEventType.Bounce:
                thisEvent = new MantaBounceEvent();
                FillMantaBounceEvent((thisEvent as MantaBounceEvent), record);
                break;

            case MantaEventType.TimedOutInQueue:
                thisEvent = new MantaTimedOutInQueueEvent();
                break;

            default:
                throw new NotImplementedException("Unknown Event Type (" + type + ")");
            }

            thisEvent.EmailAddress = record.GetString("evn_event_emailAddress");
            thisEvent.EventTime    = record.GetDateTime("evn_event_timestamp");
            thisEvent.EventType    = type;
            thisEvent.ID           = record.GetInt32("evn_event_id");
            thisEvent.SendID       = record.GetString("snd_send_id");
            thisEvent.Forwarded    = record.GetBoolean("evn_event_forwarded");
            return(thisEvent);
        }
Exemple #2
0
        public void SaveAndGetBounce()
        {
            using (CreateTransactionScopeObject())
            {
                MantaBounceEvent originalEvt = new MantaBounceEvent
                {
                    BounceInfo = new BouncePair
                    {
                        BounceCode = MantaBounceCode.BadEmailAddress,
                        BounceType = MantaBounceType.Hard
                    },
                    EmailAddress = "*****@*****.**",
                    EventTime    = DateTime.UtcNow,
                    EventType    = MantaEventType.Bounce,
                    Message      = "550 Invalid Inbox",
                    SendID       = "qwerty"
                };

                originalEvt.ID = EventsManager.Instance.Save(originalEvt);

                MantaBounceEvent savedEvt = (MantaBounceEvent)EventsManager.Instance.GetEvent(originalEvt.ID);

                Assert.NotNull(savedEvt);
                Assert.AreEqual(originalEvt.BounceInfo.BounceCode, savedEvt.BounceInfo.BounceCode);
                Assert.AreEqual(originalEvt.BounceInfo.BounceType, savedEvt.BounceInfo.BounceType);
                Assert.AreEqual(originalEvt.EmailAddress, savedEvt.EmailAddress);
                Assert.That(savedEvt.EventTime, Is.EqualTo(originalEvt.EventTime).Within(TimeSpan.FromSeconds(1)));
                Assert.AreEqual(originalEvt.EventType, savedEvt.EventType);
                Assert.AreEqual(originalEvt.ID, savedEvt.ID);
                Assert.AreEqual(originalEvt.Message, savedEvt.Message);
                Assert.AreEqual(originalEvt.SendID, savedEvt.SendID);
            }
        }
Exemple #3
0
        public void NonDeliveryReport()
        {
            using (CreateTransactionScopeObject())
            {
                string emailContent = System.IO.File.OpenText(@".\..\..\NonDeliveryReport Test Email.eml").ReadToEnd();

                EmailProcessingDetails processingDetail = EventsManager.Instance.ProcessBounceEmail(emailContent);

                Assert.AreEqual(EmailProcessingResult.SuccessBounce, processingDetail.ProcessingResult);
                MantaEventCollection events = EventsManager.Instance.GetEvents();
                Assert.AreEqual(1, events.Count);
                Assert.IsTrue(events[0] is MantaBounceEvent);
                MantaBounceEvent bounce = (MantaBounceEvent)events[0];
                Assert.AreEqual(MantaBounceCode.BadEmailAddress, bounce.BounceInfo.BounceCode);
                Assert.AreEqual(MantaBounceType.Hard, bounce.BounceInfo.BounceType);
                Assert.AreEqual("*****@*****.**", bounce.EmailAddress);
                Assert.AreEqual("550 5.1.1 unknown or illegal alias: [email protected]", bounce.Message);
                Assert.AreEqual("TestData", bounce.SendID);
            }
        }
Exemple #4
0
        public void SmtpResponseTest()
        {
            using (CreateTransactionScopeObject())
            {
                EmailProcessingDetails processingDetails;


                bool result = EventsManager.Instance.ProcessSmtpResponseMessage("550 User Unknown", "*****@*****.**", 1, out processingDetails);
                Assert.IsTrue(result);

                MantaEventCollection events = EventsManager.Instance.GetEvents();
                Assert.AreEqual(1, events.Count);
                Assert.IsTrue(events[0] is MantaBounceEvent);
                MantaBounceEvent bounce = (MantaBounceEvent)events[0];
                Assert.AreEqual(MantaBounceCode.BadEmailAddress, bounce.BounceInfo.BounceCode);
                Assert.AreEqual(MantaBounceType.Hard, bounce.BounceInfo.BounceType);
                Assert.AreEqual("*****@*****.**", bounce.EmailAddress);
                Assert.AreEqual("550 User Unknown", bounce.Message);
                Assert.AreEqual("TestData", bounce.SendID);
            }
        }
Exemple #5
0
        /// <summary>
        /// Fills the MantaBounceEvent with values from <paramref name="record"/>
        /// </summary>
        /// <param name="evt">The MantaBounceEvent to fill.</param>
        /// <param name="record">The data record to fill with.</param>
        private static void FillMantaBounceEvent(MantaBounceEvent evt, IDataRecord record)
        {
            if (record.IsDBNull("evn_bounceCode_id"))               // The bounce record is incomplete
            {
                evt.BounceInfo = new BouncePair
                {
                    BounceCode = MantaBounceCode.Unknown,                 // Don't know what the bounce was.
                    BounceType = MantaBounceType.Soft                     // Assume soft bounce, just to be nice. If it happens 3 times sentoi will mark bad.
                };

                evt.Message = string.Empty;                 // There is no message.
            }
            else
            {
                evt.BounceInfo = new BouncePair
                {
                    BounceCode = (MantaBounceCode)record.GetInt32("evn_bounceCode_id"),
                    BounceType = (MantaBounceType)record.GetInt32("evn_bounceType_id")
                };
                evt.Message = record.GetString("evn_bounceEvent_message");
            }
        }
Exemple #6
0
        /// <summary>
        /// Examines an email to try to identify detailed bounce information from it.
        /// </summary>
        /// <param name="filename">Path and filename of the file being processed.</param>
        /// <param name="message">The entire text content for an email (headers and body).</param>
        /// <returns>An EmailProcessingResult value indicating whether the the email was
        /// successfully processed or not.</returns>
        public EmailProcessingDetails ProcessBounceEmail(string message)
        {
            EmailProcessingDetails bounceDetails = new EmailProcessingDetails();

            MimeMessage msg = MimeMessage.Parse(message);

            if (msg == null)
            {
                bounceDetails.ProcessingResult = EmailProcessingResult.ErrorContent;
                bounceDetails.BounceIdentifier = BounceIdentifier.NotIdentifiedAsABounce;
                return(bounceDetails);
            }


            // "X-Recipient" should contain what Manta originally set as the "return-path" when sending.
            MessageHeader returnPath = msg.Headers.GetFirstOrDefault("X-Recipient");

            if (returnPath == null)
            {
                bounceDetails.ProcessingResult = EmailProcessingResult.ErrorNoReturnPath;
                bounceDetails.BounceIdentifier = BounceIdentifier.UnknownReturnPath;
                return(bounceDetails);
            }

            string rcptTo         = string.Empty;
            int    internalSendID = 0;

            if (!ReturnPathManager.TryDecode(returnPath.Value, out rcptTo, out internalSendID))
            {
                // Not a valid Return-Path so can't process.
                bounceDetails.ProcessingResult = EmailProcessingResult.ErrorNoReturnPath;
                bounceDetails.BounceIdentifier = BounceIdentifier.UnknownReturnPath;
                return(bounceDetails);
            }

            MantaBounceEvent bounceEvent = new MantaBounceEvent();

            bounceEvent.EmailAddress = rcptTo;
            bounceEvent.SendID       = SendDB.GetSend(internalSendID).ID;

            // TODO: Might be good to get the DateTime found in the email.
            bounceEvent.EventTime = DateTime.UtcNow;

            // These properties are both set according to the SMTP code we find, if any.
            bounceEvent.BounceInfo.BounceCode = MantaBounceCode.Unknown;
            bounceEvent.BounceInfo.BounceType = MantaBounceType.Unknown;
            bounceEvent.EventType             = MantaEventType.Bounce;

            // First, try to find a NonDeliveryReport body part as that's the proper way for an MTA
            // to tell us there was an issue sending the email.

            BouncePair bouncePair;
            string     bounceMsg;
            BodyPart   deliveryReportBodyPart;
            string     deliveryReport = string.Empty;

            if (FindFirstBodyPartByMediaType(msg.BodyParts, "message/delivery-status", out deliveryReportBodyPart))
            {
                // If we've got a delivery report, check it for info.

                // Abuse report content may have long lines whitespace folded.
                deliveryReport = MimeMessage.UnfoldHeaders(deliveryReportBodyPart.GetDecodedBody());

                if (ParseNdr(deliveryReport, out bouncePair, out bounceMsg, out bounceDetails))
                {
                    // Successfully parsed.
                    bounceEvent.BounceInfo = bouncePair;
                    bounceEvent.Message    = bounceMsg;

                    // Write BounceEvent to DB.
                    Save(bounceEvent);

                    bounceDetails.ProcessingResult = EmailProcessingResult.SuccessBounce;
                    return(bounceDetails);
                }
            }



            // We're still here so there was either no NDR part or nothing contained within it that we could
            // interpret so have to check _all_ body parts for something useful.
            if (FindBounceReason(msg.BodyParts, out bouncePair, out bounceMsg, out bounceDetails))
            {
                bounceEvent.BounceInfo = bouncePair;
                bounceEvent.Message    = bounceMsg;

                // Write BounceEvent to DB.
                Save(bounceEvent);

                bounceDetails.ProcessingResult = EmailProcessingResult.SuccessBounce;
                return(bounceDetails);
            }



            // Nope - no clues relating to why the bounce occurred.
            bounceEvent.BounceInfo.BounceType = MantaBounceType.Unknown;
            bounceEvent.BounceInfo.BounceCode = MantaBounceCode.Unknown;
            bounceEvent.Message = string.Empty;

            bounceDetails.BounceIdentifier = BounceIdentifier.NotIdentifiedAsABounce;
            bounceDetails.ProcessingResult = EmailProcessingResult.Unknown;
            return(bounceDetails);
        }
Exemple #7
0
        /// <summary>
        /// Examines an SMTP response message to identify detailed bounce information from it.
        /// </summary>
        /// <param name="response">The message that's come back from an external MTA when attempting to send an email.</param>
        /// <param name="rcptTo">The email address that was being sent to.</param>
        /// <param name="internalSendID">The internal Manta SendID.</param>
        /// <returns>True if a bounce was found and recorded, false if not.</returns>
        internal bool ProcessSmtpResponseMessage(string response, string rcptTo, int internalSendID, out EmailProcessingDetails bounceIdentification)
        {
            bounceIdentification = new EmailProcessingDetails();



            // Check for TimedOutInQueue message first.
            if (response.Equals(MtaParameters.TIMED_OUT_IN_QUEUE_MESSAGE, StringComparison.OrdinalIgnoreCase))
            {
                bounceIdentification = null;

                MantaTimedOutInQueueEvent timeOut = new MantaTimedOutInQueueEvent
                {
                    EventType    = MantaEventType.TimedOutInQueue,
                    EmailAddress = rcptTo,
                    SendID       = SendDB.GetSend(internalSendID).ID,
                    EventTime    = DateTime.UtcNow
                };

                // Log to DB.
                Save(timeOut);

                // All done return true.
                return(true);
            }



            BouncePair bouncePair    = new BouncePair();
            string     bounceMessage = string.Empty;


            if (ParseBounceMessage(response, out bouncePair, out bounceMessage, out bounceIdentification))
            {
                // Were able to find the bounce so create the bounce event.
                MantaBounceEvent bounceEvent = new MantaBounceEvent
                {
                    EventType    = MantaEventType.Bounce,
                    EmailAddress = rcptTo,
                    BounceInfo   = bouncePair,
                    SendID       = SendDB.GetSend(internalSendID).ID,
                    // It is possible that the bounce was generated a while back, but we're assuming "now" for the moment.
                    // Might be good to get the DateTime found in the email at a later point.
                    EventTime = DateTime.UtcNow,
                    Message   = response
                };

                // Log to DB.
                Save(bounceEvent);


                // All done return true.
                return(true);
            }



            // Couldn't identify the bounce.

            bounceIdentification.BounceIdentifier = BounceIdentifier.NotIdentifiedAsABounce;

            return(false);
        }