Exchange 2010 SP2 Routing agent:

A) to route platform internal traffic of the
platform
B) To ensure internal OOF are not delivered to other platform tenants


The WSP Exchange SP2 Transport Agent is responsible for the following:
A) Determine that an email is being sent between tenants on the same system,
and re-routes the mail to deliver to a smart host elsewhere in the network, for
 subsequent routing back to Exchange.
B) Since Exchange Server 2007, a user has been able to set both an internal and
 an external OOF, and have Exchange deliver the OOF based on the sender being
 inside or outside the same Exchange Organization. In a multi-tenant
 configuration of Exchange such as that described in this document, all users
 in all tenants are considered internal to each other, and so the Internal OOF
 is sent between them if emails are exchange and OOF is set on a mailbox.
 The transport agent will prohibit to exchange internal OOF between different tenants
The transport agent will override the recipient destination for inter tenant
email exchange to an alternative domain. The platform will have a send
connector defined pointing assigned to the alternative domain name space and
pointing to the next hop, a smart hosts (This can be a Windows SMTP Service).
The smarthost will have a smarthost defined as well that will route back
the message to the platform.
Perform the following steps:
A)	Copy the files WSPTransportAgent.dll and WSPTransportAgent.dll.config
to “C:\Program Files\Microsoft\Exchange Server\V14\Public”
B)	Import the WSPTransportAgent.reg to create the event source
C)	Use the registry editor and provide the” NETWORK SERVICE” Full Control
on the following Key
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\WSPTransportAgent
D	Run the following powershell command in the exchange management shell:
	Install-TransportAgent “WSPTransportAgent” –TransportAgentFactory
        WSPTransportAgent.MEACPRoutingAgentFactory
        –AssemblyPath
 “C:\Program Files\Microsoft\Exchange Server\V14\Public\WSPTransportAgent.dll”
D)	Enable-TransportAgent “WSPTransportAgent”
E)	Restart the Microsoft Exchange Transport Service
The configuration file contains the following configurable items:
Key	Value
A) routingDomain	This is the alternative domain that will be added to
the recipient domain name. This should be aligned with the namespace for the
send connector. A sample value could be “.tmp”. The send connector will in
that case serve the  *.tmp namespace
logFile	Full qualified path to log file that will be used when verbose logging
is enabled (e.g. c:\temp\WSP.log)
enableVerboseLogging	Possible values: true or false. Enables or disables
verbose logging. This should be disabled by default
blockInternalInterTenantOOF	Possible values: true or false.
Enabled the internal auto reply between tenants. Auto replies within the
tenant or with external tenants (not hosted on the platform) will receive the
internal or external auto reply message.

See http://www.microsoft.com/en-us/download/details.aspx?id=28192
This commit is contained in:
robvde 2012-07-10 12:17:19 +04:00
parent a240fcebc6
commit 697e7f23c8
9 changed files with 390 additions and 0 deletions

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections/>
<appSettings>
<add key="routingDomain" value=".tmp"/>
<add key="logFile" value="C:\Temp\WSP.Log"/>
<add key="enableVerboseLogging" value="false"/>
<add key="blockInternalInterTenantOOF" value="true"/>
</appSettings>
</configuration>

View file

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WSPTransportAgent")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WSPTransportAgent")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e28cac4e-9660-4174-8010-c6a00c81bf57")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,260 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Configuration;
using System.Collections.ObjectModel;
using System.Collections;
using System.Collections.Specialized;
using System.Xml;
using Microsoft.Exchange.Data.Transport;
using Microsoft.Exchange.Data.Transport.Routing;
using Microsoft.Exchange.Data.Mime;
using System.DirectoryServices;
namespace WSPTransportAgent
{
public class WSPRoutingAgentFactory : RoutingAgentFactory
{
public override RoutingAgent CreateAgent(SmtpServer server)
{
return new WSPRoutingAgent(server);
}
}
public class WSPRoutingAgent : RoutingAgent
{
private string routingDomain;
private bool enableVerboseLogging;
private string logFile;
private Hashtable htAcceptedDomains;
private bool blockInternalInterTenantOOF;
public WSPRoutingAgent(SmtpServer server)
{
//subscribe to different events
loadConfiguration();
WriteLine("WSPRoutingAgent Registration started");
loadAcceptedDomains(server);
//GetAcceptedDomains();
WriteLine("\trouting Domain: " + routingDomain);
base.OnResolvedMessage += new ResolvedMessageEventHandler(WSPRoutingAgent_OnResolvedMessage);
WriteLine("WSPRoutingAgent Registration completed");
}
private void loadConfiguration()
{
this.routingDomain = ".tmpdefault";
this.enableVerboseLogging = true;
this.logFile = "C:\\WSP.LOG";
try
{
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = System.Reflection.Assembly.GetExecutingAssembly().Location + ".config";
Configuration libConfig = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
AppSettingsSection section = (libConfig.GetSection("appSettings") as AppSettingsSection);
this.routingDomain = section.Settings["routingDomain"].Value;
this.enableVerboseLogging = (section.Settings["enableVerboseLogging"].Value == "true");
this.blockInternalInterTenantOOF = (section.Settings["blockInternalInterTenantOOF"].Value == "true");
this.logFile = section.Settings["logFile"].Value;
}
catch (Exception ex)
{
WriteLine("\t[Error] " + ex.Message);
LogErrorToEventLog("[Error] [loadConfiguration] Error :" + ex.Message);
}
}
private void loadAcceptedDomains(SmtpServer server)
{
try
{
if (htAcceptedDomains == null)
this.htAcceptedDomains = new Hashtable();
else
this.htAcceptedDomains.Clear();
foreach (AcceptedDomain domain in server.AcceptedDomains)
{
htAcceptedDomains.Add(domain.ToString(), "1");
WriteLine("\tAccepted Domain: " + domain.ToString());
}
}
catch (Exception ex)
{
WriteLine("\t[Error] " + ex.Message);
LogErrorToEventLog("[Error] [loadAcceptedDomains] Error :" + ex.Message);
}
}
void WSPRoutingAgent_OnResolvedMessage(ResolvedMessageEventSource source, QueuedMessageEventArgs e)
{
try
{
WriteLine("Start WSPRoutingAgent_OnResolvedMessage");
WriteLine("\tFromAddress: " + e.MailItem.FromAddress.ToString());
WriteLine("\tSubject: " + e.MailItem.Message.Subject.ToString());
WriteLine("\tMapiMessageClass: " + e.MailItem.Message.MapiMessageClass.ToString());
MimeDocument mdMimeDoc = e.MailItem.Message.MimeDocument;
HeaderList hlHeaderlist = mdMimeDoc.RootPart.Headers;
Header mhProcHeader = hlHeaderlist.FindFirst("X-WSP");
if (mhProcHeader == null)
{
WriteLine("\tTouched: " + "No");
if (!e.MailItem.Message.IsSystemMessage)
{
bool touched = false;
if (e.MailItem.FromAddress.DomainPart != null)
{
foreach (EnvelopeRecipient recp in e.MailItem.Recipients)
{
WriteLine("\t\tTo: " + recp.Address.ToString().ToLower());
if (IsMessageBetweenTenants(e.MailItem.FromAddress.DomainPart.ToLower(), recp.Address.DomainPart.ToLower()))
{
WriteLine("\t\tMessage routed to domain: " + recp.Address.DomainPart.ToLower() + routingDomain);
RoutingDomain myRoutingDomain = new RoutingDomain(recp.Address.DomainPart.ToLower() + routingDomain);
RoutingOverride myRoutingOverride = new RoutingOverride(myRoutingDomain, DeliveryQueueDomain.UseOverrideDomain);
source.SetRoutingOverride(recp, myRoutingOverride);
touched = true;
}
}
}
else
{
if ((e.MailItem.Message.MapiMessageClass.ToString() == "IPM.Note.Rules.OofTemplate.Microsoft") &
blockInternalInterTenantOOF)
{
WriteLine("\t\tOOF From: " + e.MailItem.Message.From.SmtpAddress);
if (e.MailItem.Message.From.SmtpAddress.Contains("@"))
{
string[] tmp = e.MailItem.Message.From.SmtpAddress.Split('@');
foreach (EnvelopeRecipient recp in e.MailItem.Recipients)
{
WriteLine("\t\tTo: " + recp.Address.ToString().ToLower());
if (IsMessageBetweenTenants(tmp[1].ToLower(), recp.Address.DomainPart.ToLower()))
{
WriteLine("\t\tRemove: " + recp.Address.DomainPart.ToLower());
e.MailItem.Recipients.Remove(recp);
}
}
}
}
}
if (touched)
{
MimeNode lhLasterHeader = hlHeaderlist.LastChild;
TextHeader nhNewHeader = new TextHeader("X-WSP", "Logged00");
hlHeaderlist.InsertBefore(nhNewHeader, lhLasterHeader);
}
}
else
WriteLine("\tSystem Message");
}
else
WriteLine("\tTouched: " + "Yes");
}
catch (Exception ex)
{
WriteLine("\t[Error] Error :" + ex.Message);
LogErrorToEventLog("[Error] [OnResolvedMessage] Error :" + ex.Message);
}
WriteLine("End WSPRoutingAgent_OnResolvedMessage");
}
private bool IsMessageBetweenTenants(string senderDomain, string recipientDomain)
{
if (senderDomain == recipientDomain) return false;
if ((htAcceptedDomains[senderDomain] != null) &&
(htAcceptedDomains[recipientDomain] != null))
return true;
return false;
}
/*
private void GetAcceptedDomains()
{
try
{
htAcceptedDomains.Clear();
DirectoryEntry rdRootDSE = new DirectoryEntry("LDAP://RootDSE");
DirectoryEntry cfConfigPartition = new DirectoryEntry("LDAP://" + rdRootDSE.Properties["configurationnamingcontext"].Value);
DirectorySearcher cfConfigPartitionSearch = new DirectorySearcher(cfConfigPartition);
cfConfigPartitionSearch.Filter = "(objectClass=msExchAcceptedDomain)";
cfConfigPartitionSearch.SearchScope = SearchScope.Subtree;
SearchResultCollection srSearchResults = cfConfigPartitionSearch.FindAll();
foreach (SearchResult srSearchResult in srSearchResults)
{
DirectoryEntry acDomain = srSearchResult.GetDirectoryEntry();
htAcceptedDomains.Add(acDomain.Properties["msexchaccepteddomainname"].Value.ToString().ToLower(), "1");
WriteLine("\tAccepted Domain :" + acDomain.Properties["msexchaccepteddomainname"].Value.ToString().ToLower());
}
}
catch (Exception ex)
{
WriteLine("\tError :" + ex.Message);
EventLog.WriteEntry("WSP Transport Agent", ex.Message, EventLogEntryType.Error);
}
}
*/
private void WriteLine(string Line)
{
if (!enableVerboseLogging) return;
try
{
StreamWriter writer = new StreamWriter(logFile, true, System.Text.Encoding.ASCII);
writer.WriteLine("[" + DateTime.Now.ToString() + "]" + Line);
writer.Close();
}
catch (Exception e)
{
}
}
private void LogErrorToEventLog(string Line)
{
try
{
if (EventLog.SourceExists("WSPTransportAgent"))
{
EventLog.WriteEntry("WSPTransportAgent", Line, EventLogEntryType.Error);
}
}
catch (Exception ex)
{
WriteLine("[Error] WritingEventLog :" + ex.Message);
}
}
}
}

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{D959F137-A56F-4F4E-BA80-599FBE3700E3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WSPTransportAgent</RootNamespace>
<AssemblyName>WSPTransportAgent</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Exchange.Data.Common">
<HintPath>..\..\Lib\References\Microsoft\Microsoft.Exchange.Data.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Exchange.Data.Transport">
<HintPath>..\..\Lib\References\Microsoft\Microsoft.Exchange.Data.Transport.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.DirectoryServices" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="WSPRoutingAgent.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="WSPTransportAgent.reg" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,15 @@
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\MEACPTransportAgent]
"MaxSize"=dword:00080000
"AutoBackupLogFiles"=dword:00000000
"Retention"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\MEACPTransportAgent\MEACPTransportAgent]
"EventMessageFile"=hex(2):43,00,3a,00,5c,00,57,00,69,00,6e,00,64,00,6f,00,77,\
00,73,00,5c,00,4d,00,69,00,63,00,72,00,6f,00,73,00,6f,00,66,00,74,00,2e,00,\
4e,00,45,00,54,00,5c,00,46,00,72,00,61,00,6d,00,65,00,77,00,6f,00,72,00,6b,\
00,36,00,34,00,5c,00,76,00,34,00,2e,00,30,00,2e,00,33,00,30,00,33,00,31,00,\
39,00,5c,00,45,00,76,00,65,00,6e,00,74,00,4c,00,6f,00,67,00,4d,00,65,00,73,\
00,73,00,61,00,67,00,65,00,73,00,2e,00,64,00,6c,00,6c,00,00,00

View file

@ -43,6 +43,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Plugins.PayPal
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Templates", "WebsitePanel.Templates\WebsitePanel.Templates.csproj", "{387FA0EF-3927-45FF-8F8F-BCCD735540C6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WSPTransportAgent", "WSPTransportAgent\WSPTransportAgent.csproj", "{D959F137-A56F-4F4E-BA80-599FBE3700E3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -107,6 +109,10 @@ Global
{387FA0EF-3927-45FF-8F8F-BCCD735540C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{387FA0EF-3927-45FF-8F8F-BCCD735540C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{387FA0EF-3927-45FF-8F8F-BCCD735540C6}.Release|Any CPU.Build.0 = Release|Any CPU
{D959F137-A56F-4F4E-BA80-599FBE3700E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D959F137-A56F-4F4E-BA80-599FBE3700E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D959F137-A56F-4F4E-BA80-599FBE3700E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D959F137-A56F-4F4E-BA80-599FBE3700E3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -106,6 +106,7 @@
<Content Include="App_Themes\Default\Images\Exchange\disabled.png" />
<Content Include="App_Themes\Default\Images\Exchange\disabled_16.png" />
<Content Include="App_Themes\Default\Images\Exchange\enabled.png" />
<Content Include="App_Themes\Default\Images\Exchange\lync16.png" />
<Content Include="App_Themes\Default\Images\FileManager\vbhtml.png" />
<Content Include="App_Themes\Default\Images\lync16.png" />
<Content Include="App_Themes\Default\Images\lync48.png" />