Share via


Block Outgoing BCC Emails

None of the transport rule predicates support matching on only BCC, so I don’t believe a basic transport rule will block outgoing BCC emails.  I think you’d have to do a transport agent (routing agent) to do what you’re looking for. Something like this might get you started:

This is just some sample code which was quickly modified. It wasn’t even put in Visual Studio, so it’s NOT TESTED AT ALL!  Sample code courtesy of Matt Stehle.

 

 

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Text;

using System.IO;

using Microsoft.Exchange.Data.Transport;

using Microsoft.Exchange.Data.Transport.Email;

using Microsoft.Exchange.Data.Transport.Routing;

 

namespace CustomNDR

{

    public sealed class CustomNDRAgentFactory : RoutingAgentFactory

    {

        public override RoutingAgent CreateAgent(SmtpServer server)

        {

            return new CustomNDR();

        }

    }

 

    public class CustomNDR : RoutingAgent

    {

        public const string NdrSubject = "Rejected Message - Original Attached";

        public const string NdrFromDisplayName = "System Administrator";

        public const string NdrFromAddress = "administrator@contoso.com";

 

        public const string OutputPath =

            @"C:\Users\Administrator\Desktop\CustomNDR\output\";

        public const string PickupPath =

            @"C:\Program Files\Microsoft\Exchange Server\TransportRoles\Pickup\";

        public CustomNDR()

        {

            LogMessage("CustomNDR{}", "Enter");

            this.OnSubmittedMessage += new SubmittedMessageEventHandler(CustomNDR_OnSubmittedMessage);

            LogMessage("CustomNDR()", "Leave");

        }

        void CustomNDR_OnSubmittedMessage(SubmittedMessageEventSource source, QueuedMessageEventArgs e)

        {

            LogMessage("OnSubmittedMessage", "Enter");

            try

            {

                // Check for BCC recipients...

                if (e.MailItem.Message.Bcc.Count > 0)

                {

                    EmailMessage origMsg = e.MailItem.Message;

                    LogMessage("OnSubmittedMessage", String.Concat("Message: ", origMsg.Subject));

                    if (Directory.Exists(OutputPath))

                    {

                        // Save a copy of the original message for debug

                        //SaveMessage(origMsg, String.Concat(OutputPath, "Original.eml"));

                        EmailMessage newMsg = EmailMessage.Create();

                        newMsg.To.Add(new EmailRecipient(origMsg.Sender.DisplayName, origMsg.Sender.SmtpAddress));

                        newMsg.From = new EmailRecipient(NdrFromDisplayName, NdrFromAddress);

                        newMsg.Subject = NdrSubject;

                        // Setting the contentType to 'message/rfc822' is the key to avoid an InvalidOperationException

                        // with a message 'Cannot set the property, the attachment is not an embedded message.'

                        Attachment attach = newMsg.Attachments.Add("RejectedMessage", "message/rfc822");

                        attach.EmbeddedMessage = origMsg;

                        // Save a copy of the NDR message for debug

                        //SaveMessage(newMsg, String.Concat(OutputPath, "newMsg.eml"));

                        // Save message to the pickup directory to send it

                        SaveMessage(newMsg, String.Concat(PickupPath, "newMsg.eml"));

                        // Cancel the original message

                        source.Delete();

                    }

                    else

                    {

                        LogMessage("OnSubmittedMessage", "OutputPath does not exist.");

                    }

                }

            }

            catch (Exception ex)

            {

                LogMessage("OnSubmittedMessage",

                    String.Format("EXCEPTION: Type={0}, Message='{1}'", ex.GetType().FullName, ex.Message));

            }

            LogMessage("OnSubmittedMessage", "Leave");

        }

        public static void SaveMessage(EmailMessage msg, string filePath)

        {

            try

            {

                FileStream file = new FileStream(filePath, System.IO.FileMode.Create);

                msg.MimeDocument.WriteTo(file);

                file.Close();

            }

            catch

            {

                LogMessage("SaveMessage",

                    String.Format("Failed to save message, {0}, to {1}.",

                        msg.Subject, filePath));

                throw;

            }

        }

        public static void LogMessage(string methodName, string message)

        {

            try

            {

                StringBuilder traceMessage = new StringBuilder();

                traceMessage.Append(System.DateTime.Now.ToString("s"));

                traceMessage.Append("|");

                traceMessage.Append(methodName);

                traceMessage.Append("|");

                traceMessage.Append(message);

                traceMessage.Append("\r\n");

                System.Diagnostics.Debug.WriteLine(traceMessage.ToString());

                File.AppendAllText(

                    String.Concat(OutputPath, "log.txt"),

                    traceMessage.ToString());

            }

            catch (Exception ex)

            {

                Debug.WriteLine(String.Format("Failed to log message, {0}, to 'log.txt' in {1}.", message, OutputPath));

                System.Diagnostics.Debug.WriteLine(String.Format("Exception: {0}", ex.Message));

            }

        }

    }

}

 

This code will block ALL messages with ANY BCC recipients, including internal to internal, so additional modification would be required to process only messages leaving the organization if that’s the desired goal. Unless obviously you have this on the Edge Transport role…

Comments

  • Anonymous
    May 25, 2011
    Hi BesirovicX! At first, thanks for the sample code and the information on the need of writting a custom transport agent for blocking BCC recipient type. I'd like to make a little comment regarding the very first phrase of this blog article though. Actually, both Exchange 2007/2010 Edge Transport servers has a OOB predicate that is able to block "To", "CC" and "BCC" recipient types, which is AnyOfRecipientAddressContains: "AnyOfRecipientAddressContains matches messages that contain the specified words in the To, Cc, or Bcc fields of the message." Best regards,