Skip to Content
Technical Articles

Ignore Operational Emails in your Suppression Logic

Introduction

With the suppression custom logic you can define rules to avoid sending too many emails to your customers and prospects (See also this blog post). Until release 2102 you could only evaluate attributes and conditions on the level of campaign, contact and interactions. Sometimes you may want to base your suppression decision also on the type of email you are really sending. In case of only one email in a campaign this could already be done by using a campaign category. However, if there are multiple emails in a campaign and some of those should be treated as ‘operational’ emails there was no way to distinguish those different emails with respect to the suppression logic.

With release 2105 we have enhanced the capabilities of the suppression custom logic to also get details on the specific email.

Example Use Case

Julia is a marketeer for the coffee company Gallo d’Oro and she prepared 2 campaigns. The spring offer campaign is scheduled for April 1 and contains a follow-up email with a special promotion. Additionally a second campaign on April 9 is planned with an invitation for our next barista event.

When Julia tests the setup of the first campaign the initial email is sent out just fine:

But after she clicked on the CTA button in the initial email she did not get the follow-up email as expected. When looking at the campaign performance she notices that that email had been suppressed.

Julia gets on the phone with the IT department and learned that there is a central suppression logic which only allows one email every 7 days for any contact. She explains to the IT expert that such follow-up emails should rather be treated as operational emails and therefore not be suppressed.

The IT expert just learned about a new enhancement in the new release and gets to work…

Implementation

Note: Every coding I show here comes without warranty or maintenance. Please use at your own risk and test carefully!

First let’s have a look at the existing suppression logic:

DATA(factory) = cl_cuan_sr_badi_api_factory=>get_instance( ).
DATA(read) = factory->create_reader( ).
DATA(suppress) = factory->create_suppressor( ).
DATA(allow) = factory->create_allowance( ).
DATA(calculate) = factory->create_calculator( ).
DATA(calendar) = factory->create_calendar( ).
DATA(log) = factory->create_logger( ).
DATA(campaign) = read->campaign( campaign_id ).
suppression_rules_result = suppression_rules_input.

IF action_id = 'SEND_EMAIL'
    suppress->with_recent_interactions(
      EXPORTING
        interaction_type = 'EMAIL_OUTBOUND'
        period           = calculate->period_days( 7 )
        count            = 1
      CHANGING
        results          = suppression_rules_result
    ).
ENDIF.

Always allow Operational Emails

The new enhancement allows to also get email data of the email that is about to be sent by the current campaign action. For example, this allows to get the communication category of that email. Gallo d’Oro IT decides to use the communication category ‘_OP’ as indicator for operational emails which should be ignored.

To accomplish this, a section in the code is introduced which allows such emails regardless of any suppression logic which had been executed before.

" ---------------------------------------------------------------------------------
"  Allow all emails with communication category '_OP' (Check attributes of outgoing email)
" ---------------------------------------------------------------------------------
IF action_id EQ if_cuan_mkt_orch_constants=>sc_action_id-send_email
AND line_exists( action_parameters[ name = if_cuan_mkt_orch_constants=>sc_action_parameter_id-email_template_id ] ).
      	" read email ID
	DATA(email_template_id) = action_parameters[ name = if_cuan_mkt_orch_constants=>sc_action_parameter_id-email_template_id ]-value.
      	" select email using CDS view
	SELECT SINGLE campaigncontentname, communicationcategoryname FROM i_mkt_campaigncontent
        	WHERE campaigncontent EQ @email_template_id INTO @DATA(email).
      	" check that email communication category equals special ID
	IF email-communicationcategoryname EQ '_OP'.
		allow->all( CHANGING results = suppression_rules_result ).
ENDIF.

After activating the new version of the custom suppression code IT asks Julia to test the process. She sets up a new follow-up email with the operational communication category ‘_OP’:

After starting a new test campaign Julia is happy with the result: The follow-up email was sent successfully:

Ignore Interactions from Operational Emails in your Suppression Logic

Remembering her second planned campaign for the barista workshop invitation Julia checks in with IT again and ask whether the operational emails would also be ignored for any following campaign. The IT expert realizes that the helper method suppress->with_recent_interactions would still consider those operational emails and therefore they replaced the method with a new code:

" ---------------------------------------------------------------------------------
"  Check for marketing e-mails in recent days but ignore operational e-mails
" ---------------------------------------------------------------------------------
DATA contact_key_ranges TYPE RANGE OF cuan_bopf_key.
contact_key_ranges = VALUE #( FOR <result> IN suppression_rules_result
    ( sign   = 'I'
      option = 'EQ'
      low    = <result>-contact_key ) ).
DATA(week_period) = calculate->period_days( 7 ).
DATA suppress_keys TYPE TABLE OF cuan_cds_interaction.

SELECT DISTINCT interactioncontact FROM i_mkt_interaction AS interaction
   INNER JOIN i_mkt_campaigncontent AS email ON email~campaigncontent = interaction~marketingorchestrationid
         AND ( email~communicationcategoryname IS NULL
         OR email~communicationcategoryname NOT LIKE '%_OP%' )
      WHERE interactiontype EQ @if_cuan_ce_c=>co_iatype_email_outbound
         AND interactioncontact IN @contact_key_ranges
         AND tstmp_seconds_between( tstmp1 = CAST( interactiontimestamputc AS DEC( 15, 0 ) ), tstmp2 = tstmp_current_utctimestamp( ) ) LE @week_period
      GROUP BY interactioncontact
      HAVING COUNT(*) GE 1
      INTO TABLE @suppress_keys.

suppress->contacts(
   EXPORTING
      contact_keys = suppress_keys
   CHANGING
      results      = suppression_rules_result
).

Testing the second campaign a few days after the first one Julia is happy that the email is sent:

Looking at the timeline of the test contact Julia can see that the proposed solution by IT does indeed work. The first campaign sent the initial email on April 1 and after a few days the email was opened and the link clicked. The operational follow-up email was successfully sent because of the allow statement for operational emails described in the last section.

But also the email of the second campaign had been sent although it would have been suppressed before that code change. This is because the time difference between the email on April 4 and April 9 would have been less than 7 days. With this code the last relevant email is the one from April 1 and here the time difference is more than 7 days and thus the email of the barista invitation had been sent.

Final Code

For your convenience I have the complete coding – but of course without any warranty.

DATA(factory) = cl_cuan_sr_badi_api_factory=>get_instance( ).
DATA(read) = factory->create_reader( ).
DATA(suppress) = factory->create_suppressor( ).
DATA(allow) = factory->create_allowance( ).
DATA(calculate) = factory->create_calculator( ).
DATA(calendar) = factory->create_calendar( ).
DATA(log) = factory->create_logger( ).
DATA(campaign) = read->campaign( campaign_id ).
suppression_rules_result = suppression_rules_input.

***************************************************************************************** 
*	Suppress/Allow involving Email Communication Category
*****************************************************************************************
IF action_id = 'SEND_EMAIL'

      " ---------------------------------------------------------------------------------
      "  Check for marketing e-mails in recent days but ignore operational e-mails
      " ---------------------------------------------------------------------------------
      DATA contact_key_ranges TYPE RANGE OF cuan_bopf_key.
      contact_key_ranges = VALUE #( FOR <result> IN suppression_rules_result
                                       ( sign   = 'I'
                                         option = 'EQ'
                                         low    = <result>-contact_key ) ).

      DATA(week_period) = calculate->period_days( 7 ).

      DATA suppress_keys TYPE TABLE OF cuan_cds_interaction.

      SELECT DISTINCT interactioncontact FROM i_mkt_interaction AS interaction
        INNER JOIN i_mkt_campaigncontent AS email ON email~campaigncontent = interaction~marketingorchestrationid
                                                 AND ( email~communicationcategoryname IS NULL
                                                    OR email~communicationcategoryname NOT LIKE '%_OP%' )
        WHERE interactiontype EQ @if_cuan_ce_c=>co_iatype_email_outbound
          AND interactioncontact IN @contact_key_ranges
          AND tstmp_seconds_between( tstmp1 = CAST( interactiontimestamputc AS DEC( 15, 0 ) ), tstmp2 = tstmp_current_utctimestamp( ) ) LE @week_period
        GROUP BY interactioncontact
        HAVING COUNT(*) GE 1
        INTO TABLE @suppress_keys.

      suppress->contacts(
        EXPORTING
          contact_keys = suppress_keys
        CHANGING
          results      = suppression_rules_result
      ).

      " ---------------------------------------------------------------------------------
      "  Allow all emails with communication category '_OP' (Check attributes of outgoing email)
      " ---------------------------------------------------------------------------------
    IF action_id EQ if_cuan_mkt_orch_constants=>sc_action_id-send_email
        AND line_exists( action_parameters[ name = if_cuan_mkt_orch_constants=>sc_action_parameter_id-email_template_id ] ).
      " read email ID
      DATA(email_template_id) = action_parameters[ name = if_cuan_mkt_orch_constants=>sc_action_parameter_id-email_template_id ]-value.
      " select email using CDS view
      SELECT SINGLE campaigncontentname, communicationcategoryname FROM i_mkt_campaigncontent
        WHERE campaigncontent EQ @email_template_id INTO @DATA(email).
      " check that email communication category equals special ID
      IF email-communicationcategoryname EQ '_OP'.
        allow->all( CHANGING results = suppression_rules_result ).
      ENDIF.
            
    ENDIF.

ENDIF.

Conclusion

After reading this post you should be able to set up your suppression logic considering the exclusion of operational emails.

Be the first to leave a comment
You must be Logged on to comment or reply to a post.