private void OnEndOfDataHandler(ReceiveMessageEventSource source, EndOfDataEventArgs e)
        {
            string[] addrs;
            //hash code is not guaranteed to be unique. Add time to fix uniqueness
            string itemId = e.MailItem.GetHashCode().ToString() + e.MailItem.FromAddress.ToString();

            if (this.origToMapping.TryGetValue(itemId, out addrs))
            {
                this.origToMapping.Remove(itemId);
                if (this.databaseConnector != null)
                {
                    this.databaseConnector.LogCatch(addrs[0], addrs[1], e.MailItem.Message.Subject, e.MailItem.Message.MessageId);
                }

                //Add / update orig to header
                if (CatchAllFactory.AppSettings.AddOrigToHeader)
                {
                    MimeDocument mdMimeDoc    = e.MailItem.Message.MimeDocument;
                    HeaderList   hlHeaderlist = mdMimeDoc.RootPart.Headers;
                    Header       origToHeader = hlHeaderlist.FindFirst("X-OrigTo");

                    if (origToHeader == null)
                    {
                        MimeNode   lhLasterHeader = hlHeaderlist.LastChild;
                        TextHeader nhNewHeader    = new TextHeader("X-OrigTo", addrs[0]);
                        hlHeaderlist.InsertBefore(nhNewHeader, lhLasterHeader);
                    }
                    else
                    {
                        origToHeader.Value += ", " + addrs[0];
                    }
                }
            }
        }
예제 #2
0
        private void EndOfDataEventHandler(ReceiveMessageEventSource source, EndOfDataEventArgs args)
        {
            if (!DeliveryThrottling.Instance.CheckAndTrackThrottleConcurrentMessageSizeLimit(args.SmtpSession.SessionId, args.MailItem.Recipients.Count))
            {
                MSExchangeStoreDriver.DeliveryRetry.Increment();
                source.RejectMessage(AckReason.MaxConcurrentMessageSizeLimitExceeded);
                return;
            }
            string internetMessageId = args.MailItem.InternetMessageId;

            if (string.IsNullOrEmpty(internetMessageId))
            {
                DeliveryThrottlingAgent.Diag.TraceWarning(0, (long)this.GetHashCode(), "MessageId header is missing. Poison handling is disabled");
                return;
            }
            int crashCount = 0;

            if (DeliveryConfiguration.Instance.PoisonHandler.VerifyPoisonMessage(internetMessageId, out crashCount))
            {
                DeliveryThrottlingAgent.Diag.TraceError <string>(0, (long)this.GetHashCode(), "Poison message identified. Message ID: {0}", internetMessageId);
                source.RejectMessage(AckReason.InboundPoisonMessage(crashCount));
                return;
            }
            PoisonHandler <DeliveryPoisonContext> .Context = new DeliveryPoisonContext(internetMessageId);
        }
 private void OnEndOfHeadersHandler(ReceiveMessageEventSource source, EndOfHeadersEventArgs e)
 {
     Logger.Debug("[GenericTransportAgent] SmtpReceiveAgent - OnEndOfHeaders fired...");
     foreach (var x in Configuration.Config.SmtpReceiveAgentConfig.OnEndOfHeaders)
     {
         try
         {
             x.Execute(new EmailItem(e.MailItem));
         }
         catch (Exception ex)
         {
             Logger.Error(ex, @"Error executing ""OnEndOfHeaders""");
         }
     }
 }
        /// <summary>
        /// This method is called if the sender address provided by the
        /// mail from command was null.
        ///
        /// Because at this point individual recipients cannot be rejected,
        /// if any recipient should be rejected, all recipients will be rejected.
        /// </summary>
        /// <param name="source">The source of the event.</param>
        /// <param name="eodArgs">The arguments passed to the event.</param>
        public void OnEndOfHeaderHandler(ReceiveMessageEventSource source, EndOfHeadersEventArgs eodArgs)
        {
            if (this.testOnEndOfHeaders)
            {
                // Reset the flag.
                this.testOnEndOfHeaders = false;

                // Get the sender address from the message header.
                Header fromAddress = eodArgs.Headers.FindFirst(HeaderId.From);
                if (fromAddress != null)
                {
                    this.senderAddress = new RoutingAddress(fromAddress.Value);
                }
                else
                {
                    // No sender address, reject the message.
                    source.RejectMessage(DelayResponseMessage);
                    return;
                }

                // Determine whether any of the recipients should be rejected, and if so, reject them all.
                bool rejectAll = false;
                foreach (EnvelopeRecipient currentRecipient in eodArgs.MailItem.Recipients)
                {
                    if (!this.ShouldBypassFilter(this.senderAddress, currentRecipient.Address, this.server) &&
                        !this.VerifyTriplet(this.senderIP, this.senderAddress, currentRecipient.Address))
                    {
                        rejectAll = true;
                    }
                }

                if (rejectAll)
                {
                    source.RejectMessage(DelayResponseMessage);
                }
            }
        }
        /// <summary>
        /// Invoked by Exchange when a message has been submitted.
        /// </summary>
        /// <param name="source">The source of this event.</param>
        /// <param name="args">Arguments for this event.</param>
        void EndOfDataHandler(ReceiveMessageEventSource source, EndOfDataEventArgs args)
        {
            Debug.WriteLine("[AntivirusAgent] Invoking the COM service");

            try
            {
                // Create the virus scanner COM object.
                Guid classGuid     = new Guid("B71FEE9E-25EF-4e50-A1D2-545361C90E88");
                Guid interfaceGuid = new Guid("7578C871-D9B3-455a-8371-A82F7D864D0D");

                object virusScannerObject = UnsafeNativeMethods.CoCreateInstance(
                    classGuid,
                    null,
                    4, // CLSCTX_LOCAL_SERVER,
                    interfaceGuid);

                this.virusScanner = (IComInvoke)virusScannerObject;

                // GetAgentAsyncContext causes Exchange to wait for this agent
                // to invoke the returned callback before continuing to
                // process the current message.
                this.agentAsyncContext = this.GetAgentAsyncContext();

                this.mailItem = args.MailItem;

                // Invoke the virus scanner.
                this.virusScanner.BeginVirusScan((IComCallback)this);
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                Debug.WriteLine("[AntivirusAgent] " + ex.ToString());
                this.agentAsyncContext.Complete();
            }

            return;
        }
 void OnEndOfHeadersHandler(ReceiveMessageEventSource source, EndOfHeadersEventArgs e)
 {
     Logger.Debug("[GenericTransportAgent] SmtpReceiveAgent - OnEndOfHeaders fired...");
     _config.SmtpReceiveAgentConfig.OnEndOfHeaders.ToList().ForEach(x => { try { x.Execute(new EmailItem(e.MailItem)); } catch (Exception ex) { Logger.Error(ex, @"Error executing ""OnEndOfHeaders"""); } });
 }
예제 #7
0
        private void OnEndOfDataHandler(
            ReceiveMessageEventSource source,
            EndOfDataEventArgs e)
        {
            string bodyAsText = "";
            StreamReader reader = new StreamReader(e.MailItem.Message.Body.GetContentReadStream(), Microsoft.Exchange.Data.Globalization.Charset.GetEncoding(e.MailItem.Message.Body.CharsetName), true);
            bodyAsText = reader.ReadToEnd();
            reader.Close();

            if ( this.ShouldBlockMessage(bodyAsText, e.MailItem.Message.Subject) ) {
                source.RejectMessage(
                    this.GetRejectResponse());
            }
        }
        /// <summary>
        /// Invoked by Exchange when the entire message has been received.
        /// </summary>
        /// <param name="source">The source of this event.</param>
        /// <param name="eodArgs">The arguments for this event.</param>
        public void OnEndOfDataHandler(ReceiveMessageEventSource source, EndOfDataEventArgs eodArgs)
        {
            Debug.WriteLine("[BodyConversion] OnEndOfDataHandler is called");

            // The purpose of this sample is to show how TextConverters can be used
            // to update the body. This sample shows how to ensure that no active
            // content, such as scripts, can pass through in a message body.

            EmailMessage message             = eodArgs.MailItem.Message;
            Stream       originalBodyContent = null;
            Stream       newBodyContent      = null;
            Encoding     encoding;
            string       charsetName;

            try
            {
                Body       body       = message.Body;
                BodyFormat bodyFormat = body.BodyFormat;

                if (!body.TryGetContentReadStream(out originalBodyContent))
                {
                    // You cannot decode the body.
                    return;
                }

                if (BodyFormat.Text == bodyFormat)
                {
                    // Plain text body. Add a disclaimer to this body.

                    charsetName = body.CharsetName;
                    if (null == charsetName ||
                        !Microsoft.Exchange.Data.Globalization.Charset.TryGetEncoding(charsetName, out encoding))
                    {
                        // Either no charset, or charset is not supported by the system.
                        return;
                    }

                    // Create and set up the TextToText conversion object.
                    TextToText textToTextConversion = new TextToText();

                    // Don't change the body code page.
                    textToTextConversion.InputEncoding = encoding;
                    // By default, the output code page is the same as the input code page.

                    // Add a disclaimer to indicate that the body is not being filtered.
                    textToTextConversion.HeaderFooterFormat = HeaderFooterFormat.Text;
                    textToTextConversion.Footer             = "the plain text body is NOT being filtered";

                    // Open the stream to write updated content into.
                    newBodyContent = body.GetContentWriteStream();

                    // Do the conversion. This will replace the original text.
                    // with an updated version.
                    try
                    {
                        // The easiest way to do the conversion in one step is by using the Convert
                        // method. It creates the appropriate converter stream
                        // and copies from one stream to another.
                        textToTextConversion.Convert(originalBodyContent, newBodyContent);
                    }
                    catch (Microsoft.Exchange.Data.TextConverters.TextConvertersException)
                    {
                        // The conversion has failed.
                    }
                }
                else if (BodyFormat.Html == bodyFormat)
                {
                    // The HTML body.

                    // Filter the original HTML to remove any scripts and other
                    // potentially unsafe content.

                    charsetName = body.CharsetName;
                    if (null == charsetName ||
                        !Microsoft.Exchange.Data.Globalization.Charset.TryGetEncoding(charsetName, out encoding))
                    {
                        // Either no charset, or charset is not supported by the system.
                        return;
                    }

                    // Create and set up the HtmlToHtml conversion object.
                    HtmlToHtml htmlToHtmlConversion = new HtmlToHtml();

                    // Don't change the body code page.
                    htmlToHtmlConversion.InputEncoding = encoding;
                    // By default, the output code page is the same as the input code page.

                    // Set up output HTML filtering. HTML filtering will ensure that
                    // no scripts or active content can pass through.
                    htmlToHtmlConversion.FilterHtml = true;

                    // Add a disclaimer to indicate that the body is being filtered.
                    htmlToHtmlConversion.HeaderFooterFormat = HeaderFooterFormat.Html;
                    htmlToHtmlConversion.Footer             = "<p><font face=\"Arial\" size=\"+1\">the HTML body is being filtered</font></p>";

                    // Open the stream to write updated content into.
                    newBodyContent = body.GetContentWriteStream();

                    // Do the conversion. This will replace the original HTML
                    // with a filtered version.
                    try
                    {
                        // The easiest way to do the conversion in one step is by using the Convert
                        // method. It creates an appropriate converter stream
                        // and copies from one stream to another.
                        htmlToHtmlConversion.Convert(originalBodyContent, newBodyContent);
                    }
                    catch (Microsoft.Exchange.Data.TextConverters.TextConvertersException)
                    {
                        // The conversion has failed.
                    }
                }
                else if (BodyFormat.Rtf == bodyFormat)
                {
                    // This is compressed RTF body in a TNEF message.

                    // Compressed RTF body can contain the encapsulated original HTML to be
                    // filtered.

                    // Do not modify the message format here, just filter out
                    // potentially unsafe content. Convert RTF to HTML, filter out any
                    // unsafe HTML content, and convert the result back to RTF.

                    // Note that conversion from RTF to HTML and back to RTF can result in loss of data. Some
                    // embedded images in RTF can be lost and formatting can slightly change.

                    // First wrap the original body content, which is in a "compressed RTF" format, into
                    // a stream that will do RTF decompression. Reading from this stream
                    // will return original RTF (the same format that the Word and RichEdit controls are using).
                    ConverterStream uncompressedRtf = new ConverterStream(originalBodyContent, new RtfCompressedToRtf(), ConverterStreamAccess.Read);

                    // Create and configure the RtfToHtml conversion object.
                    RtfToHtml rtfToHtmlConversion = new RtfToHtml();

                    // Set up output HTML filtering. HTML filtering will ensure that
                    // no scripts or active content can pass through.
                    rtfToHtmlConversion.FilterHtml = true;

                    // Add a disclaimer to indicate that the body is being filtered.
                    rtfToHtmlConversion.HeaderFooterFormat = HeaderFooterFormat.Html;
                    rtfToHtmlConversion.Footer             = "<p><font face=\"Arial\" size=1>the RTF body is being filtered</font></p>";

                    // Now create a wrapping TextReader object, which returns the filtered
                    // HTML converted (or extracted) from the original RTF.
                    ConverterReader html = new ConverterReader(uncompressedRtf, rtfToHtmlConversion);

                    // After you filter the HTML, convert it back to RTF. For the purposes of this sample, do not
                    // change the message format.

                    // Create and configure the HtmlToRtf conversion object.
                    HtmlToRtf htmlToRtfConversion = new HtmlToRtf();

                    // Create a wrapping stream that returns RTF converted back from filtered HTML.
                    ConverterStream filteredRtf = new ConverterStream(html, htmlToRtfConversion);

                    // Create and configure the RtfToRtfCompressed conversion object, which
                    // will compress the resulting RTF.
                    RtfToRtfCompressed rtfCompressionConversion = new RtfToRtfCompressed();

                    // Always write it back in a compressed form.
                    rtfCompressionConversion.CompressionMode = RtfCompressionMode.Compressed;

                    // Open the stream to write updated body content into.
                    newBodyContent = body.GetContentWriteStream();

                    // Finally, perform the complete chain of conversions you set up. This
                    // will read the original compressed RTF chunk by chunk, convert it to HTML
                    // and filter scripts, then convert HTML back to RTF, compress it and write
                    // back into the current message body.
                    try
                    {
                        // Use the Convert method because it is convenient. This Convert
                        // method compresses the resulting RTF it reads from the conversion
                        // chain stream you set up and writes the result into the output stream.
                        // It saves a few lines of code that would be required to create another wrapper stream and
                        // copy from one stream to another.
                        rtfCompressionConversion.Convert(filteredRtf, newBodyContent);
                    }
                    catch (Microsoft.Exchange.Data.TextConverters.TextConvertersException)
                    {
                        // The conversion has failed.
                    }
                }

                else
                {
                    // Handle cases where the body format is not one of the above.
                }
            }

            finally
            {
                if (originalBodyContent != null)
                {
                    originalBodyContent.Close();
                }

                if (newBodyContent != null)
                {
                    newBodyContent.Close();
                }
            }
        }
예제 #9
0
        public void OnEndOfHeaderHandler(ReceiveMessageEventSource source, EndOfHeadersEventArgs eodArgs)
        {
            if (this.testOnEndOfHeaders)
            {
                RoutingAddress senderAddress;
                // Reset the flag.
                this.testOnEndOfHeaders = false;

                // Get the sender address from the message header.
                Header fromAddress = eodArgs.Headers.FindFirst(HeaderId.From);
                if (fromAddress != null)
                {
                    senderAddress = new RoutingAddress(fromAddress.Value);
                }
                else
                {
                    this.logLine("FROM=, TO=Multiple, REMOTE=" + eodArgs.SmtpSession.RemoteEndPoint.Address.ToString() + ", STATE=Greylist, REASON=No from address.", 2);                
                    // No sender address, reject the message.
                    source.RejectMessage(DelayResponseMessage);
                    return;
                }

                // Determine whether any of the recipients should be rejected, and if so, reject them all.
                bool rejectAll = false;
                foreach (EnvelopeRecipient currentRecipient in eodArgs.MailItem.Recipients)
                {
                    if (this.ShouldBypassFilter(senderAddress, currentRecipient.Address, eodArgs.SmtpSession.RemoteEndPoint.Address))
                    {
                        continue;
                    }
                    if (!this.VerifyTriplet(eodArgs.SmtpSession.RemoteEndPoint.Address, senderAddress, currentRecipient.Address))
                    {
                        this.logLine("FROM="+senderAddress.ToString()+", TO="+currentRecipient.Address.ToString()+", REMOTE=" + eodArgs.SmtpSession.RemoteEndPoint.Address.ToString() + ", STATE=Greylist, REASON=Triplet verify failed.", 2);  
                        rejectAll = true;
                    }
                }

                if (rejectAll)
                {
                    this.logLine("FROM=" + senderAddress.ToString() + ", TO=MANY, REMOTE=" + eodArgs.SmtpSession.RemoteEndPoint.Address.ToString() + ", STATE=Greylist, REASON=One or more recipients failed Triplet verification.", 2);                
                    source.RejectMessage(DelayResponseMessage);
                    return;
                }
                this.logLine("FROM=" + senderAddress.ToString() + ", TO=MANY, REMOTE=" + eodArgs.SmtpSession.RemoteEndPoint.Address.ToString() + ", STATE=Accept, REASON=Triplets Match.", 2);                
                    
            }
        }
예제 #10
0
        public void OnEndOfHeadersHandler(ReceiveMessageEventSource source, EndOfHeadersEventArgs args)
        {
            string        messageId       = String.Empty;
            string        rejectReason    = String.Empty;
            List <Header> headersToRemove = new List <Header>();

            // Compare the message's headers with the rules.
            foreach (Header header in args.Headers)
            {
                if (header.HeaderId == HeaderId.MessageId)
                {
                    messageId = header.Value;
                }

                foreach (XHeaderRule rule in XHeaderAgent.rules)
                {
                    if (String.Equals(rule.Name, header.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        switch (rule.Action)
                        {
                        case Action.Reject:
                            rejectReason = header.Name;
                            break;

                        case Action.Remove:
                            headersToRemove.Add(header);
                            break;
                        }
                    }
                }
            }

            // Begin preparing a debug message.
            StringBuilder builder = new StringBuilder();

            builder.Append("XHeaderAgent: Message-Id \"");
            builder.Append(messageId);
            builder.Append("\", ");

            // Take action.
            if (!String.IsNullOrEmpty(rejectReason))
            {
                builder.Append("Rejected");
                builder.Append("Contains forbidden X-header");
                builder.Append(rejectReason);

                source.RejectMessage(SmtpResponse.InvalidContent);
                source.Disconnect();
            }
            else if (0 != headersToRemove.Count)
            {
                builder.Append("Removed headers");
                foreach (Header header in headersToRemove)
                {
                    builder.Append(" ");
                    builder.Append(header.Name);
                    args.Headers.RemoveChild(header);
                }
            }
            else
            {
                builder.Append("No action");
            }

            // Write the debug message.
            Debug.WriteLine(builder.ToString());

            return;
        }
 void OnEndOfDataHandler(ReceiveMessageEventSource source, EndOfDataEventArgs e)
 {
     Logger.Debug("[GenericExchangeTransportagent] [SmtpReceiveAgent] OnEndOfData fired...");
     _config.SmtpReceiveAgentConfig.OnEndOfData.ToList().ForEach(x => { try { x.Execute(new EmailItem(e.MailItem)); } catch (Exception ex) { Logger.Error(ex, @"Error executing ""OnEndOfData"""); } });
 }
예제 #12
0
 void OnEndOfHeadersHandler(ReceiveMessageEventSource source, EndOfHeadersEventArgs e)
 {
     Logger.Debug("[GenericExchangeTransportagent] [SmtpReceiveAgent] OnEndOfHeaders fired...");
     _config.SmtpReceiveAgentConfig.OnEndOfHeaders.ToList().ForEach(x => { try { x.Execute(new EmailItem(e.MailItem)); } catch (Exception ex) { Logger.Error(ex, @"Error executing ""OnEndOfHeaders"""); } });
 }