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]; } } } }
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 OnEndOfDataHandler(ReceiveMessageEventSource source, EndOfDataEventArgs e) { Logger.Debug("[GenericTransportAgent] SmtpReceiveAgent - OnEndOfData fired..."); foreach (var x in Configuration.Config.SmtpReceiveAgentConfig.OnEndOfData) { try { x.Execute(new EmailItem(e.MailItem)); } catch (Exception ex) { Logger.Error(ex, @"Error executing ""OnEndOfData"""); } } }
/// <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 OnEndOfDataHandler(ReceiveMessageEventSource source, EndOfDataEventArgs e) { Logger.Debug("[GenericTransportAgent] 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"""); } }); }
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> /// Handles processing the message once the end of the DATA SMTP stream is sent. /// </summary> /// <param name="source"></param> /// <param name="eodArgs"></param> public void OnEndOfDataHandler(ReceiveEventSource source, EndOfDataEventArgs eodArgs) { Byte[] newlineNeedle = Encoding.ASCII.GetBytes("\n"); Byte[] scoreNeedle = Encoding.ASCII.GetBytes("X-Spam-Score: "); Byte[] discardFlag = Encoding.ASCII.GetBytes("X-Spam-Discard: YES\n"); Byte[] recievedNeedle = Encoding.ASCII.GetBytes("Received: "); Byte[] indentedLineNeedle = Encoding.ASCII.GetBytes(" "); Nullable <Double> score = null; this.logger.debug("OnEndOfDataHandler Called"); // Wrap everything in a Try. This makes sure that even if something fails the message still passes through try { this.logger.info("OnEndOfDataHandler Info: FROM=" + eodArgs.MailItem.FromAddress.ToString() + ", REMOTE=" + eodArgs.SmtpSession.RemoteEndPoint.Address.ToString()); // Check to make sure SpamAssassin exists at the path it's supposed to if (!System.IO.File.Exists(this.settings.SpamassassinPath)) { this.logger.fatal("Spamassassin does not exist at path: '" + this.settings.SpamassassinPath + "'. Bypassing."); this.logger.flush(); return; } // Check to see if this is an internal message if (!eodArgs.SmtpSession.IsExternalConnection) { foreach (EnvelopeRecipient recipient in eodArgs.MailItem.Recipients) { if (recipient.Address.LocalPart.IndexOf("HealthMailbox") == 0) { this.logger.info("Health Mailbox found in recipients. Bypassing."); this.logger.flush(); } } this.logger.info("Internal Connection Found. Bypassing."); this.logger.flush(); } // Is the message too big? if (eodArgs.MailItem.MimeStreamLength > this.settings.MaxMessageSize) { this.logger.warning("Message is too large. Increase MaxMessageSize to scan larger messages. MAXSIZE=" + this.settings.MaxMessageSize.ToString() + ", MESSAGESIZE=" + eodArgs.MailItem.MimeStreamLength.ToString()); this.logger.flush(); } // Get the message stream Stream message = eodArgs.MailItem.GetMimeReadStream(); List <Byte> messageBytes = new List <Byte>(ReadFully(message)); byte[] messageByteArray = messageBytes.ToArray(); message.Close(); this.logger.debug("Message Stream Retrieved. BYTES=" + messageByteArray.Length.ToString()); // Skip the top number of recieved lines int linestart = 0; int lineend = 0; int linestartmatch = 0; for (int i = 0; i < this.settings.SkipRecieved; i++) { this.logger.debug("Skipping #" + i.ToString() + " Recieved line"); // Find the first instance of the Recieved header linestart = ByteSearch.Locate(messageByteArray, recievedNeedle, 0); // Loop until we find a line that doesn't start with a space. do { lineend = ByteSearch.Locate(messageByteArray, newlineNeedle, linestart); this.logger.debug("Located Line End: " + lineend.ToString()); linestartmatch = ByteSearch.Locate(messageByteArray, indentedLineNeedle, lineend); this.logger.debug("Located LineStartMatch:" + linestartmatch.ToString()); messageBytes.RemoveRange(linestart, lineend - linestart + 1); messageByteArray = messageBytes.ToArray(); } while (linestartmatch == lineend + 1); this.logger.debug("Finished Skipping #" + i.ToString()); } // Run spamassassin while piping stdin/stdout this.logger.debug("Starting SpamAssassin Process. PATH='" + this.settings.SpamassassinPath + "', ARGS='" + this.settings.SpamassassinArgs + "'"); Process spamassassin = new Process(); spamassassin.StartInfo.UseShellExecute = false; spamassassin.StartInfo.FileName = this.settings.SpamassassinPath; spamassassin.StartInfo.WorkingDirectory = Path.GetDirectoryName(spamassassin.StartInfo.FileName); spamassassin.StartInfo.Arguments = ("-s " + this.settings.MaxMessageSize + " " + this.settings.SpamassassinArgs).Trim(); spamassassin.StartInfo.RedirectStandardInput = true; spamassassin.StartInfo.RedirectStandardOutput = true; spamassassin.StartInfo.RedirectStandardError = true; spamassassin.Start(); this.logger.debug("Started SpamAssassin Process. PID='" + spamassassin.Id.ToString() + "'"); // Copy the message into stdio using a byte for byte copy this.logger.debug("Copying message to Spamassassin. BYTES=" + messageByteArray.Length.ToString()); spamassassin.StandardInput.BaseStream.Write(messageByteArray, 0, messageByteArray.Length); spamassassin.StandardInput.BaseStream.Flush(); spamassassin.StandardInput.BaseStream.Close(); // Read the entire output buffer, put it into a list for easy manipulation List <Byte> outBytes = new List <Byte>(ReadFully(spamassassin.StandardOutput.BaseStream)); this.logger.debug("Read STDOUT from spamassassin. BYTES=" + outBytes.Count.ToString()); spamassassin.StandardOutput.BaseStream.Close(); // Read the entire stderr buffer, place it in a file if there's anything to it Byte[] outErrorBytes = ReadFully(spamassassin.StandardError.BaseStream); this.logger.debug("Read STDERR from spamassassin. BYTES=" + outErrorBytes.Length.ToString()); if (outErrorBytes.Length > 0) { this.logger.error("Error From SpamAssassin: " + outErrorBytes.ToString()); } spamassassin.StandardError.BaseStream.Close(); // Wait for process to exit spamassassin.WaitForExit(); // Find a header int flagStart = ByteSearch.Locate(outBytes.ToArray(), scoreNeedle, 0); int scoreEnd = -1; int scoreStart = 0; // Check if we found the start of the header if (flagStart > -1) { scoreStart = flagStart + scoreNeedle.Length; scoreEnd = ByteSearch.Locate(outBytes.ToArray(), newlineNeedle, scoreStart); } else { this.logger.warning("Could not find start of score in message."); } // Check if we found the end of the header if (scoreEnd > -1) { Byte[] scoreBytes = outBytes.GetRange(scoreStart, scoreEnd - scoreStart).ToArray(); try { score = Double.Parse(new String(scoreBytes.Select(b => (Char)b).ToArray()).Trim()); } catch (Exception e) { this.logger.warning("Could not parse score. Exception:" + e.Message); } } else { this.logger.warning("Could not find end of score in message."); } // If we found a score check it and process it if (score != null) { if (score >= this.settings.RejectThreshold) { this.logger.info("Score(" + score.ToString() + ") above threshold(" + this.settings.RejectThreshold.ToString() + "), flagging for discard."); outBytes.InsertRange(flagStart, discardFlag); } else { this.logger.info("Score(" + score.ToString() + ") below threshold(" + this.settings.RejectThreshold.ToString() + "), passing."); } } // Write the message back to SpamAssassin Byte[] writeBytes = outBytes.ToArray(); Stream messageOut = eodArgs.MailItem.GetMimeWriteStream(); this.logger.debug("Writing message to MailItem. BYTES=" + writeBytes.Length.ToString()); messageOut.Write(writeBytes, 0, writeBytes.Length); messageOut.Close(); } catch (Exception e) { this.logger.fatal("Exception Detected"); this.logger.fatal(e.ToString()); } finally { this.logger.flush(); } }
/// <summary> /// Handles processing the message once the end of the DATA SMTP stream is sent. /// </summary> /// <param name="source"></param> /// <param name="eodArgs"></param> public void OnEndOfDataHandler(ReceiveEventSource source, EndOfDataEventArgs eodArgs) { Byte[] newlineNeedle = Encoding.ASCII.GetBytes("\n"); Byte[] scoreNeedle = Encoding.ASCII.GetBytes("X-Spam-Score: "); Byte[] discardFlag = Encoding.ASCII.GetBytes("X-Spam-Discard: YES\n"); Byte[] recievedNeedle = Encoding.ASCII.GetBytes("Received: "); Byte[] indentedLineNeedle = Encoding.ASCII.GetBytes(" "); Nullable<Double> score = null; this.logger.debug("OnEndOfDataHandler Called"); // Wrap everything in a Try. This makes sure that even if something fails the message still passes through try { this.logger.info("OnEndOfDataHandler Info: FROM=" + eodArgs.MailItem.FromAddress.ToString() + ", REMOTE=" + eodArgs.SmtpSession.RemoteEndPoint.Address.ToString()); // Check to make sure SpamAssassin exists at the path it's supposed to if (!System.IO.File.Exists(this.settings.SpamassassinPath)) { this.logger.fatal("Spamassassin does not exist at path: '" + this.settings.SpamassassinPath + "'. Bypassing."); this.logger.flush(); return; } // Check to see if this is an internal message if (!eodArgs.SmtpSession.IsExternalConnection) { foreach (EnvelopeRecipient recipient in eodArgs.MailItem.Recipients) { if (recipient.Address.LocalPart.IndexOf("HealthMailbox") == 0) { this.logger.info("Health Mailbox found in recipients. Bypassing."); this.logger.flush(); } } this.logger.info("Internal Connection Found. Bypassing."); this.logger.flush(); } // Is the message too big? if (eodArgs.MailItem.MimeStreamLength > this.settings.MaxMessageSize) { this.logger.warning("Message is too large. Increase MaxMessageSize to scan larger messages. MAXSIZE=" + this.settings.MaxMessageSize.ToString() + ", MESSAGESIZE=" + eodArgs.MailItem.MimeStreamLength.ToString()); this.logger.flush(); } // Get the message stream Stream message = eodArgs.MailItem.GetMimeReadStream(); List<Byte> messageBytes = new List<Byte>(ReadFully(message)); byte[] messageByteArray = messageBytes.ToArray(); message.Close(); this.logger.debug("Message Stream Retrieved. BYTES=" + messageByteArray.Length.ToString()); // Skip the top number of recieved lines int linestart = 0; int lineend = 0; int linestartmatch = 0; for (int i = 0; i < this.settings.SkipRecieved; i++) { this.logger.debug("Skipping #" + i.ToString() + " Recieved line"); // Find the first instance of the Recieved header linestart = ByteSearch.Locate(messageByteArray, recievedNeedle, 0); // Loop until we find a line that doesn't start with a space. do { lineend = ByteSearch.Locate(messageByteArray, newlineNeedle, linestart); this.logger.debug("Located Line End: " + lineend.ToString()); linestartmatch = ByteSearch.Locate(messageByteArray, indentedLineNeedle, lineend); this.logger.debug("Located LineStartMatch:" + linestartmatch.ToString()); messageBytes.RemoveRange(linestart, lineend - linestart + 1); messageByteArray = messageBytes.ToArray(); } while (linestartmatch == lineend + 1); this.logger.debug("Finished Skipping #" + i.ToString()); } // Run spamassassin while piping stdin/stdout this.logger.debug("Starting SpamAssassin Process. PATH='" + this.settings.SpamassassinPath + "', ARGS='" + this.settings.SpamassassinArgs + "'"); Process spamassassin = new Process(); spamassassin.StartInfo.UseShellExecute = false; spamassassin.StartInfo.FileName = this.settings.SpamassassinPath; spamassassin.StartInfo.WorkingDirectory = Path.GetDirectoryName(spamassassin.StartInfo.FileName); spamassassin.StartInfo.Arguments = ("-s " + this.settings.MaxMessageSize + " " + this.settings.SpamassassinArgs).Trim(); spamassassin.StartInfo.RedirectStandardInput = true; spamassassin.StartInfo.RedirectStandardOutput = true; spamassassin.StartInfo.RedirectStandardError = true; spamassassin.Start(); this.logger.debug("Started SpamAssassin Process. PID='" + spamassassin.Id.ToString() + "'"); // Copy the message into stdio using a byte for byte copy this.logger.debug("Copying message to Spamassassin. BYTES=" + messageByteArray.Length.ToString()); spamassassin.StandardInput.BaseStream.Write(messageByteArray, 0, messageByteArray.Length); spamassassin.StandardInput.BaseStream.Flush(); spamassassin.StandardInput.BaseStream.Close(); // Read the entire output buffer, put it into a list for easy manipulation List<Byte> outBytes = new List<Byte>(ReadFully(spamassassin.StandardOutput.BaseStream)); this.logger.debug("Read STDOUT from spamassassin. BYTES=" + outBytes.Count.ToString()); spamassassin.StandardOutput.BaseStream.Close(); // Read the entire stderr buffer, place it in a file if there's anything to it Byte[] outErrorBytes = ReadFully(spamassassin.StandardError.BaseStream); this.logger.debug("Read STDERR from spamassassin. BYTES=" + outErrorBytes.Length.ToString()); if (outErrorBytes.Length > 0) { this.logger.error("Error From SpamAssassin: " + outErrorBytes.ToString()); } spamassassin.StandardError.BaseStream.Close(); // Wait for process to exit spamassassin.WaitForExit(); // Find a header int flagStart = ByteSearch.Locate(outBytes.ToArray(), scoreNeedle, 0); int scoreEnd = -1; int scoreStart = 0; // Check if we found the start of the header if (flagStart > -1) { scoreStart = flagStart + scoreNeedle.Length; scoreEnd = ByteSearch.Locate(outBytes.ToArray(), newlineNeedle, scoreStart); } else { this.logger.warning("Could not find start of score in message."); } // Check if we found the end of the header if (scoreEnd > -1) { Byte[] scoreBytes = outBytes.GetRange(scoreStart, scoreEnd - scoreStart).ToArray(); try { score = Double.Parse(new String(scoreBytes.Select(b => (Char)b).ToArray()).Trim()); } catch(Exception e) { this.logger.warning("Could not parse score. Exception:" + e.Message); } } else { this.logger.warning("Could not find end of score in message."); } // If we found a score check it and process it if(score != null) { if (score >= this.settings.RejectThreshold) { this.logger.info("Score(" + score.ToString() + ") above threshold(" + this.settings.RejectThreshold.ToString() + "), flagging for discard."); outBytes.InsertRange(flagStart, discardFlag); } else { this.logger.info("Score(" + score.ToString() + ") below threshold(" + this.settings.RejectThreshold.ToString() + "), passing."); } } // Write the message back to SpamAssassin Byte[] writeBytes = outBytes.ToArray(); Stream messageOut = eodArgs.MailItem.GetMimeWriteStream(); this.logger.debug("Writing message to MailItem. BYTES=" + writeBytes.Length.ToString()); messageOut.Write(writeBytes, 0, writeBytes.Length); messageOut.Close(); } catch (Exception e) { this.logger.fatal("Exception Detected"); this.logger.fatal(e.ToString()); } finally { this.logger.flush(); } }
/// <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(); } } }
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"""); } }); }