Use Emails as Custom Activities in SFMC

Use Emails as Custom Activities in SFMC

When I saw Journey Builder Custom Activities for the first time, I asked “Can I build it only with Marketing Cloud?”. The simple answer was “No.”. You cannot build a whole custom activity just in Marketing Cloud. At least as long as you think about the standard way using the installed package, JWT, config.json and so on. You find a short explanation why you need an external web server in this thread on stackoverflow.

As the title suggests I want to create a similar solution using emails. My goal is to provide a draft for two functionalities that often are handled by Custom Activities.

  1. Send a contact record to an external system/channel
  2. Do a decision split based on external data

The basis – how will it work

Since it is not possible to create a real Custom Activity, I thought about other ways to run any code in Journeys. The solution is email. Here I can use AMPScript and Server Side JavaScript. With this I can do API calls or use the platform functions. I will use them to send the trigger to an external system and write a log in Marketing Cloud. The external system would then process the record. This could be used to send a message in a custom channel, to create a case, task or opportunity in a CRM or to start any other action. Afterwards I do not really want the email to be sent. Therefore I will stop the send for the specific subscriber after the code did run using the RaiseError function. The journey will continue after that.

The custom channel

Let’s think about how a custom channel activity normally works. When the contact reaches the activity, Journey Builder sends a contact record to an external system/endpoint and waits for a status to return. For SFMC that’s it. The external system will then do the processing. For security Marketing Cloud uses a JSON Web Token (JWT). From an email you can use the HTTP.Post function to send a record to an external system. 

As a very simple example I just used the authentication endpoint of Marketing Cloud. In a real use case this would be your external system. You can use the response again to write it into a data extension for logging and reporting. To ensure security in a productive environment I would do any way of authentication first and encrypt the record I am sending, for example using AMPScript.

This is how my logging Data Extension looks like:

Example logging Data Extension

Example Code for the email:

%%[
/*Only do the script while send*/ 
 IF _messagecontext == 'SEND' THEN
 Set @subscriberkey = _subscriberkey
]%%


<script runat="server">
Platform.Load("Core","1.1.1");

var subkey= Variable.GetValue("@subscriberkey");  
  
var authEndpoint = 'https://XXXXXXXXXXXXXXXXXXXXXX.auth.marketingcloudapis.com';
var payload = {
        client_id: "XXXXXXXXXXXXXXXXXXXXXX",
        client_secret: "XXXXXXXXXXXXXXXXXXXXXXX",
 grant_type: "client_credentials"
    };
var url = authEndpoint + '/v2/token';  
var contentType = 'application/json';

/*Get an access_token. This can be replaced with your endpoint. Include the data you need in your specific API call.*/

try {
   var accessTokenRequest = HTTP.Post(url, contentType, Stringify(payload));
   if(accessTokenRequest.StatusCode == 200) {
        var tokenResponse = Platform.Function.ParseJSON(accessTokenRequest.Response[0]);
        var accessToken = tokenResponse.access_token;
     Write(accessToken);

/*Write the response into a data extension*/     
      var saveDE = Platform.Function.InsertDE("Test_Write",["ContactKey","TokenValue"],[subkey,accessToken]);
     
   }
} catch (error) {
/*You could also write an error in the Data Extension*/
    Write(Stringify(error));
}
</script>

%%[
/*Stop the send*/
RaiseError('Do not send to subscriber', true)
ENDIF 
]%%

After the email has been sent in the journey, you will see some records in the Data Extension. In a productive setup this could be the logging of your requests or responses.

Example filled logging Data Extension

The custom Decision Split

From the first example it is very easy to create a custom split in Journey Builder. You probably will use the HTTP.Get function in these cases to get data from an external system.

The script it is quite the same:

  1. Send a request to an external system. Include the contact information you need.
  2. Get the response and write it into a data extension.
  3. Stop the email send.

Now you want to do the Decision Split. Therefore you first need to link the Data Extension you just filled in an Attribute Group in Contact Builder. Afterwards it is possible to use it in a normal Decision Split. As you probably know, Journey Builder cannot really work with one-to-many-relationships. Consider this in your Data Extension and the insert/update/upsert process. 

Linked Data Extension
Data Extension linked in Contact Builder

When you use the script in a journey I would also give it a small moment to finish the writing process before I do the Decision Split.

Journey with custom email activity
Decision Split after an Email Activity

Advantages of this solution

To be honest this is only a proof of concept. It is a way if you have limited resources in development and are not able to host a Custom Activity anywhere else. Since developing a Custom Activity the first time is quite complex, it can be faster to do it with Marketing Cloud resources. It could also be a simple way if you use it only rarely so that developing a Custom Activity would be oversized. Many systems and services offer interfaces that can work with these simple HTTP requests. Compared to Custom Activities, you can even use the emails outside of Journey Builder.

Comparison to a “real” custom activity

Pricing

If you use a real Custom Activity you have to host it on a web server. Salesforce would sell you Heroku for this which is working great but also needs to be paid. As a company that uses Marketing Cloud you will probably have your own servers. So this could be used as well. On the other hand every action you do via this stopped email activity will consume a super message. Consider whether the solution is worth it under these circumstances.

Performance & processes

I would expect that the performance of a Custom Activity is better than rendering an email every time and stopping it again. In addition you still need a process on the other side that takes the data from Marketing Cloud, does whatever you want it to do with the data and sends a response back to Journey Builder before the timeout of the function is reached. If you develop an external application anyway, you should not stop at the Custom Activity in favor of this workaround.

Error handling, monitoring and reporting

With this solution you use emails in a way they are not designed for. The result is that you need to build your own ways for error handling, monitoring and reporting. In SFMC it will be shown as an errored email in Email Studio and completed activity in Journey Builder. So it is also possible that it has a bad impact on the rest of your reporting. Make sure that you use the transactional send classification to ensure that Einstein features do not get any wrong numbers.

Errored Email Send

Development and usage

Using emails as custom activity you are limited to their AMPScript and JavaScript functions. You cannot use any external libraries. The real magic will happen outside of Marketing Cloud anyway. Right now when a Custom Activity fails, the contact will stop at this point of the journey. When the Email Activity fails, the contact will continue with the next step in the journey. This should be considered. In addition as a user you do not have a graphical interface to configure the activity like in a Custom Activity but probably need to adapt the code. This process is thus quite error-prone.

Conclusion

As shown it is somehow possible to create some kind of activity that sends contact records to an external system or collects data to do a decision split. The usability of this solution will not be as stable and user-friendly as you can build it in a real Custom Activity and if you need to create an application anyway I would not save effort at this point. The monitoring and reporting of real Custom Activities is also bad and must be extended by yourself. But using the email can also have an impact on your other reports. As the final point I have to mention the performance again. I don’t know if it will work properly with large quantities of contacts. So all in all I would not really use this solution in an enterprise environment. In a small project or a one-time use case I would consider whether it is appropriate.

Update:

Jonas gave me a great tip for an even better solution. Instead of putting the code in the email you can use a Code Snippet in an Exclusion Script. This works as follows: The Exclusion Script runs before the email send. Here you link your Code Snippet for example using ContentBlockbyID. In this Code Snippet you include the script I put in the email. Afterwards you just need to make sure that the script returns the value “true” so the email will not be sent. With this you save the Super Message and don’t get any wrong numbers in the reporting. Thanks for the suggestion Jonas!

Leave a Reply

Your email address will not be published. Required fields are marked *