Personalization String Troubleshooting

Personalization String Troubleshooting



Personalization strings are made up of percent signs combined with an attribute's column name, such as %%FirstName%%. When the email is sent, it is validated and each personalization string is rendered.

WHEN WE BUILT AN EMAIL , WE USE EMAIL PERSONALIZATION STRING EXTENSIVELY. IT'S RECOMMENDED TO USE LOOKUP FUNCTION INSTEAD OF EMAIL PERSONALIZATIONS.

WHY EMAILS ARE NOT SENT ? 👇

One of the most common use case is HARD ERROR. Hard error occurs due to various reasons :

  1.  Suppression list
  2.  List Detective
  3.  Exclusion list
  4.  Personalization 
First 3 are very easy to troubleshoot :
Go to the journey, point to the email activity, under the email activity, click on the view contact details ,  open email summary activity, click on the link to Summary and navigate to the hard error tab.

You find the below details:



Personalization Issue is the most difficult process of troubleshooting

I have built these content block to troubleshoot the the personalization issue: PERSONALIZATIONLOG

<script runat="server">
  Platform.Load("Core","1.1.1");
  try{
</script>
%%[
 IF EMPTY(@PERSONALIZATIONSTRING) THEN
   SET @ERROROCCURRED='TRUE'
 ENDIF
]%%
<script runat="server">
  var ERROROCCURRED= Variable.GetValue("@ERROROCCURRED");
  if(ERROROCCURRED=='TRUE'){
    var PERSONALIZATIONSTRING= Variable.GetValue("@PERSONALIZATIONSTRING");
    var PERSONALIZATIONSTRINGNAME=Variable.GetValue("@PERSONALIZATIONSTRINGNAME");
    var SUBSCRIBERKEYVALUE=Variable.GetValue("@SUBSCRIBERKEYVALUE");
    var JOBIDVALUE=Variable.GetValue("@JOBIDVALUE");
    var LOGERRORDE= DataExtension.Init("PERSONALIZATIONLOG");
    var ERRORMESSAGE='ERRORMESSAGE';
    var ISEMAILSENT='ISEMAILSENT';
    var ERRORAPICODE='ERRORCODE';
    var ERRORNUMBER='ERRORNUMBER';
    var SUBSCRIBERKEY='SUBSCRIBERKEY';
    var JOBID='JOBID';
    if(PERSONALIZATIONSTRING=='')
    {
      var MESSAGE=PERSONALIZATIONSTRINGNAME+' MISSING';
      var ERRORTYPE='VALIDATION';
      var ERRORCODE='500';
      LOGERRORDE.Rows.Add({
        SUBSCRIBERKEY:SUBSCRIBERKEYVALUE,
        ERRORMESSAGE:ERRORMESSAGE,
        ISEMAILSENT:ISEMAILSENT,
        ERRORCODE:ERRORCODE,
        ERRORNUMBER:ERRORNUMBER,
        JOBID:JOBIDVALUE}
                         );
    }
  }
  }
  catch(e){
    var SUBSCRIBERKEYVALUE=Variable.GetValue("@SUBSCRIBERKEYVALUE");
    var JOBIDVALUE=Variable.GetValue("@JOBIDVALUE");
    var ERRORMESSAGE=e.message;
    var ERRORTYPE='EXCEPTION';
    var ERRORCODE='501';
    LOGERRORDE.Rows.Add({
      SUBSCRIBERKEY:SUBSCRIBERKEYVALUE,
      ERRORMESSAGE:ERRORMESSAGE,
      ISEMAILSENT:ISEMAILSENT,
      ERRORCODE:ERRORCODE,
      ERRORNUMBER:ERRORNUMBER,
      JOBID:JOBIDVALUE}
                       );
  }
</script>
%%[
  SET @LOGERRORDE='PERSONALIZATIONLOG'
  SET @ERRORMESSAGE='ERRORMESSAGE'
  SET @ISEMAILSENT='ISEMAILSENT'
  SET @ERRORAPICODE='ERRORCODE'
  SET @ERRORNUMBER='ERRORNUMBER'
  SET @SUBSCRIBERKEY='SUBSCRIBERKEY'
  SET @SUBSCRIBERKEYVALUE=_subscriberkey
  SET @JOBIDVALUE=JOBID
  SET @JOBID='JOBID'
  IF EMPTY(@PERSONALIZATIONSTRING) THEN
   SET @MESSAGE=CONCAT(@PERSONALIZATIONSTRINGNAME,' MISSING')
   SET @ERRORTYPE='VALIDATION'
   SET @ERRORCODE=500
   RaiseError(@MESSAGE, FALSE,@ERRORTYPE,@ERRORCODE,1)
  ENDIF
]%%



BUILD A TROUBLESHOOTING EMAIL AND PASTE THE BELOW CODE SNIPPET : PERFORM PREVIEW & TEST 

Preview & Test with those subscribers you did not receive email. Recommend you to add your own personalization and test. Below code snippet checks email personalization that is reserved by SFMC.

%%[
SET @PERSONALIZATIONSTRING=_subscriberkey
SET @PERSONALIZATIONSTRINGNAME='SUBSCRIBERKEY'
]%%.
%%=ContentBlockbyKEY("PERSONALIZATIONLOG")=%%



%%[
SET @PERSONALIZATIONSTRING=emailaddr
SET @PERSONALIZATIONSTRINGNAME='EMAIL ADDRESS'
]%%.
%%=ContentBlockbyKEY("PERSONALIZATIONLOG")=%%



%%[
SET @PERSONALIZATIONSTRING=_emailid
SET @PERSONALIZATIONSTRINGNAME='EMAIL ID'
]%%.
%%=ContentBlockbyKEY("PERSONALIZATIONLOG")=%%


%%[
SET @PERSONALIZATIONSTRING=emailname_
SET @PERSONALIZATIONSTRINGNAME='EMAIL NAME'
]%%.

%%=ContentBlockbyKEY("PERSONALIZATIONLOG")=%%



TO FIND OUT WHO DID NOT RECEIVED EMAIL





RAISE ERROR :


All 5 parameters are important while calling RaiseError function. By default the 2nd parameter is set to "false".
Which means you are aborting all sends and the trigger send will stop the send.
If you set it to "True" , you are skipping the current send for the subscriber
whose personalization is not available currently.


DETERMINE WHETHER TO SKIP THE SUBSRIBER OR ABORT :

MAKE THE DECISION IN RUNTIME

%%[
    SET @RAISE_ERROR = IIF(NOT EMPTY(@PERSONALIZATIONSTRING), 'FALSE', 'TRUE')
    SET @SEND_EMAIL = IIF(EMPTY(@ISMANDATORY), 'TRUE', 'FALSE')
    IF (@RAISE_ERROR=='TRUE') THEN
      SET @MESSAGE=CONCAT(@PERSONALIZATIONSTRINGNAME,' IS MISSING')
      RaiseError(@MESSAGE,@SEND_EMAIL,'VALIDATION ERROR',3,1)
    ENDIF
]%%


IF ITS MANDATORY FOR ALL SEND AND IS CRITICAL TO BUSINESS :


    %%[
    SET @PERSONALIZATIONSTRING=emailaddr
    SET @PERSONALIZATIONSTRINGNAME='EMAIL ADDRESS'
    SET @ISMANDATORY='YES'
    ]%%
    %%=ContentBlockbyKEY("PERSONALIZATIONERROR")=%%
   
   
    %%[
    SET @PERSONALIZATIONSTRING=_subscriberkey
    SET @PERSONALIZATIONSTRINGNAME='SUBSCRIBERKEY'
    SET @ISMANDATORY='YES'
    ]%%
    %%=ContentBlockbyKEY("PERSONALIZATIONERROR")=%%
   
   
    %%[
    SET @PERSONALIZATIONSTRING=emailname_
    SET @PERSONALIZATIONSTRINGNAME='EMAIL NAME'
    SET @ISMANDATORY='YES'
    ]%%
    %%=ContentBlockbyKEY("PERSONALIZATIONERROR")=%%
   
    %%[
    SET @PERSONALIZATIONSTRING=memberid
    SET @PERSONALIZATIONSTRINGNAME='MEMBERID'
    SET @ISMANDATORY='YES'
    ]%%
    %%=ContentBlockbyKEY("PERSONALIZATIONERROR")=%%

IF NOT MANDATORY FOR ALL SEND AND WANT TO SKIP FOR THE CURRENT SUBSCRIBER :

IF MARKET DECIDES TO SKIP ONLY THOSE WHO CONTAINS BAD DATA

%%[
    SET @PERSONALIZATIONSTRING=emailaddr
    SET @PERSONALIZATIONSTRINGNAME='EMAIL ADDRESS'
   // SET @ISMANDATORY='YES' // SKIP THE SEND FOR THIS USER
]%%
    %%=ContentBlockbyKEY("PERSONALIZATIONERROR")=%%


HOW TO LOG PERSONALIZATION ERRORS INTO A LOGGING DE :

NOTE: Because the system pre-processes and builds these emails, tracking and reporting numbers include these emails despite the errors and may cause inaccuracies. Use this function to handle the errors of a small number of subscribers, rather than as a method to segment out large numbers of subscribers. Instead, use query activities and exclusion lists to handle your segmentation needs.


BEFORE YOU START YOUR JOURNEY SENDS, RUN  THIS AS SSJS SCRIPT ACTIVITY IN AUTOMATION : 👇

<script runat="server">
  Platform.Load("Core","1.1.1");
  var PERSONALIZATIONLOGDE= DataExtension.Init("PERSONALIZATIONLOGDE");
  var subscriberkey,firstName,lastName,email;
  var config = {
    name: "TargetDataExtensionName",
    cols: ["Email", "SubscriberKey", "First_Name", "Last_Name"],
    filter:  {
      LeftOperand:{
        Property:"SubscriberKey",
        SimpleOperator: "isNotNull",
        Value: " "
      }
      ,
      LogicalOperator:"AND",
      RightOperand:{
        Property:"EmailConsent",
        SimpleOperator:"equals",
        Value:"True"
      }
    }
  }
  var records = retrieveRecords(config);
  try{
    if (records.length>0){
      for(var i=0;i<records.length;i++){
        subscriberkey=records[i].Subscriber_Key;
        if(!subscriberkey){
          PERSONALIZATIONLOGDE.Rows.Add({
      ERRORMESSAGE:"Subscriberkey is missing",ERRORCODE:'303',ERRORTYPE:'Validation',SUBSCRIBERKEY:subscriberkey}
                                 );
        }
        firstName=records[i].First_Name;
         if(!firstName){
          PERSONALIZATIONLOGDE.Rows.Add({
      ERRORMESSAGE:"First Name is missing",ERRORCODE:'303',ERRORTYPE:'Validation',SUBSCRIBERKEY:subscriberkey}
                                 );
        }
        lastName=records[i].Last_Name;
        if(!lastName){
          PERSONALIZATIONLOGDE.Rows.Add({
      ERRORMESSAGE:"Last Name is missing",ERRORCODE:'303',ERRORTYPE:'Validation',SUBSCRIBERKEY:subscriberkey}
                                 );
        }
        email=records[i].Email_Consent;
        if(!email){
          PERSONALIZATIONLOGDE.Rows.Add({
      ERRORMESSAGE:"Email is missing",ERRORCODE:'303',ERRORTYPE:'Validation',SUBSCRIBERKEY:subscriberkey}
                                 );
        }
      }
    }
  }
  catch(e){
    PERSONALIZATIONLOGDE.Rows.Add({
      ERRORMESSAGE:e.message,ERRORCODE:'404',ERRORTYPE:'Exception',SUBSCRIBERKEY:subscriberkey}
                                 );
  }
  function retrieveRecords(config) {
    var prox = new Script.Util.WSProxy();
    var records = [],
        moreData = true,
        reqID = data = null;
    while (moreData) {
      moreData = false;
      if (reqID == null) {
        data = prox.retrieve("DataExtensionObject[" + config.name + "]", config.cols, config.filter);
      }
      else {
        data = prox.getNextBatch("DataExtensionObject[" + config.name + "]", reqID);
      }
      if (data != null) {
        moreData = data.HasMoreRows;
        reqID = data.RequestID;
        for (var i = 0; i < data.Results.length; i++) {
          var result_list = data.Results[i].Properties;
          var obj = {
          };
          for (k in result_list) {
            var key = result_list[k].Name;
            var val = result_list[k].Value
            if (key.indexOf("_") != 0) obj[key] = val;
          }
          records.push(obj);
        }
      }
    }
    return records;
  }
</script>



USE DECISION SPLIT OR FILTER OUT THESE RECORDS BEOFRE EMAIL ACTIVITY IN JOURNEY BUILDER. ☝



Comments

Most Viewed

CLOUD PAGE ENABLEMENT - PART 1

EMAIL NOT SENT IN JOURNEY BUILDER

CONSIDERATIONS FOR JOURNEY BUILDER

Understanding Transactional Messaging

Preference Center Demystified


Knowledge Article

Popular Posts

CLOUD PAGE ENABLEMENT - PART 1

EMAIL NOT SENT IN JOURNEY BUILDER

CONSIDERATIONS FOR JOURNEY BUILDER

Understanding Transactional Messaging

Preference Center Demystified

Journey Builder REST API Documentation

Share with Friends

Disclaimer:

The information provided on this technical blog is for general informational purposes only. As a SFMC (Salesforce Marketing Cloud) Technical Architect, I strive to offer accurate and up-to-date content related to SFMC and its associated technologies. However, please note that technology is constantly evolving, and the information provided may become outdated or inaccurate over time.

The content published on this blog represents my personal views and experiences as a SFMC Technical Architect and does not necessarily reflect the official views or opinions of any organization or employer I may be affiliated with.

While I make every effort to ensure the accuracy and reliability of the information presented, I cannot guarantee its completeness, suitability, or applicability to your specific circumstances. Therefore, it is essential to verify any information provided and make your own independent assessments or seek professional advice if needed.

Furthermore, any actions taken based on the information provided on this blog are at your own risk. I shall not be held liable for any damages, losses, or inconveniences arising from the use of the information presented here.

Please keep in mind that SFMC and its associated technologies are complex and require technical expertise for proper implementation and management. It is recommended to consult with qualified professionals or official SFMC documentation for comprehensive guidance.

Finally, please note that any product or company names mentioned on this blog are trademarks or registered trademarks of their respective owners. The mention of these trademarks or registered trademarks does not imply any endorsement or affiliation with the blog.

By accessing and using this blog, you agree to the terms of this disclaimer. If you do not agree with any part of this disclaimer, please refrain from using this blog.