A quick browse through the Sitecore config finds the following publish events:

<event name="publish:complete">
<event name="publish:complete:remote">

You may notice that by default Sitecore does most of it's events processing in the publish:end event. However there are a few problems with the publish:end event, firstly it isn't called for every language that is published and it isn't possible to easily get a list of all the languages that were published.

The publish:complete event by contrast actually gives you a PublishOption instance for each language that was published allowing us to be more selective about the actions we perform.

The two events are called by the NotifyComplete method of the PublishManager and for the local publish:complete events this works fine however there is a problem with the publish:complete:remote event, it doesn't get called!

An investigation into why quickly reveals that no event subscriber has been setup to listen for the events in the Event Queue. These listeners are normally configured by the Sitecore.Eventing.Remote.RemoteEventMap class as part of the Initialize pipeline.

This problem is easily fixed, first by creating a custom EventArgs class:

    public class PublishCompletedRemoteEventArgs : EventArgs, IPassNativeEventArgs
        public PublishCompletedRemoteEvent Event { get; private set; }

        public PublishCompletedRemoteEventArgs(PublishCompletedRemoteEvent @event)
            Event = @event;

We now need to create our own RemoteEventMap class:

    public class RemoteEventMap
        private static void OnPublishCompletedRemoteEvent(PublishCompletedRemoteEvent @event)
            Assert.ArgumentNotNull((object)@event, "event");
            Event.RaiseEvent("publish:complete:remote", (IPassNativeEventArgs)new PublishCompletedRemoteEventArgs(@event));

        public static void Initialize()

        private static void SetupSubscribers()

        public void InitializeFromPipeline(PipelineArgs args)

And finally register this with the initialize pipeline:

        <processor type="MyAssembly.RemoteEventMap, MyAssembly" method="InitializeFromPipeline"/>

With this we can now create events that subscribe remotely to the publish:complete:remote event:

        public void PublishCompleteRemote(object sender, EventArgs args)
            var pubCompleteArgs = args as PublishCompletedRemoteEventArgs;

            if (pubCompleteArgs != null)
                PublishCompletedRemoteEvent publishEvent = pubCompleteArgs.Event;

Now time to test this, we could deploy to our server infrastructure to test this but if anything goes wrong it is hard to debug. Instead we can inject events locally. To do this perform a publish locally and then open the EventQueue table in SQL Management studio. Using the query below find the Publish Complete Event you just created:

   SELECT TOP 1000 [Id]
  FROM [EuroConsumers.Sitecore.core].[dbo].[EventQueue]
  WHERE InstanceType LIKE '%PublishComplete%'

Using the Publish Complete event you found we can inject a fake event into the Event Queue. Copy the data from your event but change the InstanceName to something random and use "Default" and "GetDate()" for the Stamp and Created fields:

  INSERT INTO [EventQueue]
	'Sitecore.Eventing.Remote.PublishCompletedRemoteEvent, Sitecore.Kernel, Version=8.0.5215.0, Culture=neutral, PublicKeyToken=null',
	'Sitecore.Eventing.Remote.PublishCompletedRemoteEvent, Sitecore.Kernel, Version=8.0.5215.0, Culture=neutral, PublicKeyToken=null',

If you have the debugger attached you should notice that a couple of seconds after injecting the event your break point is hit.

You should be now able to use the publish:compelte:remote event and also create fake events to test your implementation!