How to write Exchange 2007 transport agents



As noted in the earlier E12 Developer’s Roadmap blog post, managed agents (or “Transport Agents”) have replaced transport event sinks and EDK Gateways in Exchange Server 2007. Exchange 2007 transport rules are very flexible, so why bother writing a transport agent? There are still some configuration options not covered by rules. Actually, transport rules are really just built-in transport agents. Both Edge and Hub Transport servers have these built-in agents. Custom agents give you almost unlimited options when mail passes through the transport pipeline.

Suppose you want to send all inbound mail for a certain domain to a single mailbox? For some small organizations that is an attractive solution. An SMTP transport agent is the answer. Be careful with custom agents, though. Agents have full access to all messages they process. Agents that have performance or security flaws can affect your server in ways you might not anticipate. Extensive lab testing is a must. Now that the disclaimer is out of the way, let’s dig into creating, installing, and troubleshooting an agent.

First of all, a transport agent requires Exchange Server 2007 configured with the Edge or Hub Server Roles. You will also need the .NET Framework 2.0 SDK, and Visual Studio 2005.

Decide whether you want to write an SMTP receive agent or a routing agent. Routing agents are best for mail internal to your Exchange organization, and SMTP receive agents are best for incoming SMTP mail. Each agent type defines a specific set of events that are available in the context in which they run. Visual Studio’s IntelliSense is a big help here.

Setting up the Environment and Writing the Agent

1. In Visual Studio 2005, create a new Windows C# project with the Class Library template.

2. Copy Microsoft.Exchange.Data.Transport.dll and Microsoft.Exchange.Data.Common.dll (from the C:\Program Files\Microsoft\Exchange Server\Public directory) on the Exchange 2007 server to a directory on the machine you are running the IDE on (VS 2005). Typically I’ll copy to the \debug directory for the project. Although the .Common assembly isn’t required to build a very simple agent, it has useful namespaces in it such as the Data.ContentTypes,Tnef , Data.TextConverters namespace, and Data.Mime to name a few.

3. In VS 2005 Solution Explorer, expand your project, right-click “References” and Add reference… browse to the two DLLs you copied locally, and add them.

Note:

With beta builds of Exchange 2007, a transport agent project depends on the build of the assemblies you use- in other words, if you build the project with a certain build of the above-mentioned DLLs, your class library will only run on an Exchange server of that build. If your Exchange 2007 Server gets upgraded, you need to copy the new version of Microsoft.Exchange.Data.Transport.dll and Microsoft.Exchange.Data.Common.dll locally, remove the reference to the old dll and add a new reference to the new DLLs, rebuild the project.

This should hold true only until Exchange 2007 releases. After that point, it’s my understanding that Exchange will allow earlier builds of agents to run on later builds of Exchange. So if and when Exchange Server 2007 SP1 comes out, from what I know at this point, we shouldn’t have to rebuild our Exchange 2007 transport agents.

4. Now for the coding. You’ve got the project with the added references ready. Now add using directives for these DLLs (see sample code below).

In your code, if you are using an SMTP Receive agent, implement the following derived classes that inherit from these classes:


  • SmtpReceiveAgentFactory
  • SmtpReceiveAgent

If you are writing a routing agent, your classes must inherit from these two classes:


  • RoutingAgentFactory
  • RoutingAgent

These agent factory and agent classes provide base properties and methods for accessing transport events and messages. In the agent factory derived class, override the CreateAgent method so that it returns a new instance of your agent class. Here is a sample routing agent that adds the administrator as another recipient if mail is sent to jimbob. The mail that gets to jimbob does not say that it was also sent to the administrator, unless jimbob would look at the full message headers. This agent also writes an event to the applicaton log.

Please see the blog post attachment (RoutingAgent1.cs at the bottom of this post) for the sample agent code.

A sample SMTP receive agent can be found here.

5. Use the Exchange Management Shell to install and enable the agent:

Install-TransportAgent -Name “SteveRouting” -TransportAgentFactory “SteveRoutingAgent.SampleRoutingAgentFactory” -AssemblyPath “C:\myagents\SteveRoutingAgent.dll”

6. Exit the shell to complete the installation.

7. Then run:

Enable-TransportAgent -Identity “SteveRouting”

(view installed/enabled agents with get-transportAgent)

8. Restart the MSExchangeTransport service.

If your agent writes to the application log, you must grant the Network Service Full Control over HKLM\System CCS\services\Eventlog key.

If using an SMTP receive agent, to test your agent after installation, you may need to allow telnet tests from external domains. To do so, modify the default SMTP Receive Connector at:

ADSIEDIT\Configuration\Services\Microsoft Exchange\<org name>\Administrative Groups\<your AG>\servers\<your server>\Protocols\SMTP receive connectors\default connector.

Allow anonymous user full control (you could get more granular than that).


Troubleshooting Transport Agents


The application log is the best place to start. If you agent doesn’t run correctly, it may cause the Transport service to crash. Look for errors/warnings from the MSExchangeTransport service for clues to the problem.

Pipeline tracing can help you verify that your agent is acting as you intended. Pipeline tracing copies the complete contents of e-mail messages that are sent from the e-mail account that is configured by using the PipelineTracingSenderAddress parameter on the Set-TransportServer cmdlet. Set appropriate permissions on the PipelineTracingPath folder in a production environment to avoid possible exposure of confidential information. Here’s how you enable pipeline tracing from the shell:

[MSH] C:\>Set-TransportServer servername -PipelineTracingSenderAddress someone@somewhere.com -PipelineTracingEnabled $true -PipelineTracingPath c:\pipelineTracing

When a message comes through the pipeline from the PipelineTracingSenderAddress, .eml files are created in the C:\pipelinetracing\MessageSnapshots\<GUID> directory from each stage in the transport pipeline. I traced my routing agent and in the last .eml file I see:



X-MessageSnapshot-Record-Id: 3

X-MessageSnapshot-Source: OnSubmittedMessage,SteveRouting

X-Sender: joeuser@domain.com

X-Receiver: jimbob@domain.com

X-Receiver: administrator@domain.com

X-EndOfInjectedXHeaders: MessageSnapshot-End injected headers


Opening the message headers can also help troubleshoot problems. In this case, opening the message (with Outlook Express), File, Properties, Details tab shows the following info:


X-CreatedBy: MessageSnapshot-Begin injected headers

X-MessageSnapshot-UTC-Time: 2006-10-23T21:00:07.221Z

X-MessageSnapshot-Record-Id: 3

X-MessageSnapshot-Source: OnSubmittedMessage,SteveRouting

X-Sender: joeuser@domain.com

X-Receiver: jimbob@domain.com

X-Receiver: administrator@domain.com

X-EndOfInjectedXHeaders: MessageSnapshot-End injected headers


Steve Schiemann

Additional resources:

Transport Agents

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ExSDKIntroduction/html/2f3c8dd1-7640-49e2-9168-a8af6fd2f29e.asp

Using Pipeline Tracing to Diagnose Transport Agent Issues

http://www.microsoft.com/technet/prodtechnol/exchange/E2k7Help/f3f5aa26-a83b-4430-a6f0-271878e635c0.mspx?mfr=true

How to Enable Pipeline Tracing

http://www.microsoft.com/technet/prodtechnol/exchange/E2k7Help/e7780499-9a6f-48b1-aea8-df88ecd8b18a.mspx?mfr=true

Overview of Transport Agents

http://www.microsoft.com/technet/prodtechnol/exchange/E2k7Help/e7389d63-3172-40d5-bf53-0d7cd7e78340.mspx?mfr=true

Transport Agent Commands

http://www.microsoft.com/technet/prodtechnol/exchange/E2k7Help/681d4212-4068-45bc-b986-ebe90156ead5.mspx?mfr=true

Overview of Transport Rules

http://www.microsoft.com/technet/prodtechnol/exchange/E2k7Help/e7389d63-3172-40d5-bf53-0d7cd7e78340.mspx?mfr=true

E12 Developer Roadmap

http://msexchangeteam.com/archive/2005/09/15/410941.aspx

Comments (12)
  1. Lasse says:

    Do agents have access/permission on mailboxes? For example read calendar or contacts data?

  2. Steve Schiemann says:

    Agents have full access to all messages they process. However, I don’t think they can access messages outside of the transport pipeline.

  3. Erik says:

    Imagine you need to implement a configurable transport agent. What is the standard way to achieve this? (I.e. the configuration storage, provide some GUI to user, etc.)

  4. SteveSchiemann says:

    By a configurable transport agent, an example might be an SMTP agent that reads a list of sender names or domains from some location and takes a particular action on those messages…let me know if you have something drastically different in mind.

    It really depends on the scope of the agent- is it a routing agent installed on Hub servers that should act on all internal mail? If so, those configuration details should probably be stored in Active Directory-which is fine for MS built-in agents, but for custom agents, you may have to extend the schema which is not to be done lightly.

    If it’s an SMTP agent install on Edge, the configuration would be stored in the local registry or file system.

    I hope this answer helps- let me know if more is needed.

  5. oscar says:

    Is there a transport agent or equivlant mechanisms on Unified Messaging service as well?

    I am writing an applcation, which needs to react to various UM events such as inbound/outbound call and record greeting.

  6. SteveSchiemann says:

    I don’t believe this functionality is publicly available in UM- I’ve done some informal questioning around here was referred to http://www.microsoft.com/speech/default.mspx, also was told that the events you mention here (inbound/outbound call and record greeting) are not going to be exposed from a mailbox.  The only way you can learn info of this nature from UM will be the event log. Sorry not more help, you may want to open up a ticket with our support team to get more info.

  7. Howard says:

    Hi, does Microsoft support writing agents in all managed languages? The only examples I’ve seen are all C#, can you write an agent in CLIC++ (or Managed C++ as it used to be called)?

    Thanks

  8. SteveSchiemann says:

    Yes you can write transport agents in all managed languages.

  9. Howard says:

    Thanks for the previous reply. What steps are involved in getting an agent dll to be certified by Microsoft as "works with Exchange 2007"? Or is this service even available to agents? If an agent was to be able to be certified what would that allow us to use the Microsoft certified logo when distributing the agent dll (whatever managed language it’s written in)? I’ve had a good search but found nothing regarding this topic.

    Thanks

  10. Steve Schiemann says:

    There is no such certification process in place. To me it seems like it would be tough to "certify" customer code- even if we tested it for success/performance, Microsoft would have no control over changes to the agent. At this point, the disclaimer at http://technet.microsoft.com/en-us/library/e7389d63-3172-40d5-bf53-0d7cd7e78340.aspx says it all-no certification but careful testing is a must.

  11. Anonymous says:

    I haven&amp;#39;t blogged in a while because I have been buried in work writing a new ticketing system based

Comments are closed.

Skip to main content