SAP Hybris Marketing on-Premise allows to design and send highly personalized and dynamic emails, as Jan describes in his blog entry. Unfortunately, some email clients and mobile devices don’t support all HTML and/or CSS style elements such as CSS positioning or external stylesheets. Some email clients even block all images in emails by default.

These issues can get resolved by including a “view in browser” link to a browser-friendly version of the email. When recipients click the “view in browser” link, it opens a web page in their browser that displays the online version of the email. This way, any recipients whose email client or device doesn’t support all elements can still see the email the way it was intended to be seen.

Depending on the template, one of the following links can be added to the header or (less usual) in the footer of the email content:

  • View this email in your browser
  • Email not displaying correctly? View it in your browser.

The setup of the “view in browser” link within the Content Studio is shown below:

Once a recipient clicked on the “view in browser” link, SAP Hybris Marketing will automatically fetch the personalized email and open a web page in their browser that displays the online version of the email. The overall process in summarized below:

In more detail, the script (in this context a PHP script was used) on the web server is being called using the outbound ID from the personalized “view in browser” link. The “view in browser” OData service is then being called by the script using the same outbound ID.

The responsibility of the OData service is to return the personalized mail for a given outbound ID. The outbound ID can be used to uniquely identify both the personalization attributes (e.g. first name = Tim) for the recipient and the email content (e.g. Hybris FC mail) which was used by the email campaign. An exemplary logic which can be used to determine the email content (or more specifically: the email content ID) by the outbound ID is shown below in method GET_CONTENT_ID.

* +-------------------------------------------------------------------------------------------------+
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_EXEC_HASH                   TYPE        /BOBF/CONF_KEY
* | [<-()] RV_CONTENT_ID                  TYPE        CUAN_ME_ENGAGEMENT_ID
* +-------------------------------------------------------------------------------------------------+

      lt_key              TYPE /bobf/t_frw_key,
      lt_action_parameter TYPE cuan_t_marketing_orc_act_par.

    DATA(lo_srv_mktorc)  = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( iv_bo_key = if_cuan_marketing_orch_c=>sc_bo_key ).

    APPEND VALUE #( key = iv_exec_hash ) TO lt_key.

        iv_node_key    = if_cuan_marketing_orch_c=>sc_node-execution_run
        iv_association = if_cuan_marketing_orch_c=>sc_association-execution_run-to_parent
        it_key         = lt_key
        et_target_key  = DATA(lt_action_key) ).

        iv_node_key    = if_cuan_marketing_orch_c=>sc_node-action
        iv_association = if_cuan_marketing_orch_c=>sc_association-action-action_parameter
        it_key         = lt_action_key
        iv_fill_data   = abap_true
        et_data        = lt_action_parameter ).

* read content ID from action parameter
    READ TABLE lt_action_parameter ASSIGNING FIELD-SYMBOL(<ls_action_parameter>)
          WITH KEY parameter_id = if_cuan_mkt_orch_constants=>sc_action_parameter_id-email_template_id.
    IF sy-subrc IS INITIAL.
      rv_content_id = <ls_action_parameter>-parameter_value.


In the next step, the personalization attributes have to be determined using the outbound ID. The personalization attributes are persisted in the table CUAND_EXEC_HASH (UTF-8 encoded as JSON structure in the PLACEHOLDER_VALUES field). Combining both the personalization information and the email content, the personalized mail can be re-built. The exemplary method GET_HTML_CONTENT is shown below:

* +-------------------------------------------------------------------------------------------------+
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_EXEC_HASH                   TYPE        CUAN_MKT_EXEC_HASH
* | [--->] IV_CONTENT_ID                  TYPE        CUAN_ME_ENGAGEMENT_ID
* | [--->] IT_PLACEHOLDERS                TYPE        CUAN_T_ME_DYNAMIC_CONTENT
* | [<-()] RV_HTML                        TYPE        STRING
* +-------------------------------------------------------------------------------------------------+
  METHOD get_html_content.

    DATA lo_email_handler TYPE REF TO cl_cuan_mkt_exec_email.
    DATA lt_parameters TYPE cuan_t_mkt_exec_param.
    DATA lr_dynamic_content TYPE REF TO cuan_t_me_dynamic_content.
    DATA lt_outbounds TYPE cuan_t_mkt_exec_pers_content.
    DATA ls_outbound TYPE cuan_s_mkt_exec_pers_content.
    DATA lv_path TYPE string.

        CREATE OBJECT lo_email_handler TYPE cl_cuan_mkt_exec_email_amzn EXPORTING it_parameters = lt_parameters.
      CATCH cx_root.
        MESSAGE e012(cuan_mkt_exec_frw) INTO DATA(lv_message) WITH 'CL_CUAN_MKT_EXEC_EMAIL_AMZN'.

    CREATE DATA lr_dynamic_content.
    lr_dynamic_content->* = it_placeholders.
    ls_outbound-dynamic_content = lr_dynamic_content.

    ls_outbound-email_message_ref = lo_email_handler.
    ls_outbound-personalization_hash = iv_exec_hash.

    APPEND ls_outbound TO lt_outbounds.

    lv_path = me->get_tracking_path( ).

    cl_cuan_a_me_personalize=>convert_message( EXPORTING iv_campaign_content_id = iv_content_id
                                                         iv_host                = lv_path
                                               CHANGING  ct_contacts            = lt_outbounds ).

    rv_html = lo_email_handler->if_cuan_mkt_exec_email~get_body_html( ).


The overall process is shown in the picture below:

Once the personalized email has been re-built, it is returned from the OData service and handed over 1:1 by the service in order to display it in the web browser. Additionally, the service on the customer webserver can be adapted in a way that is displays content or redirects to a specific URL as a fallback option when the backend is not reachable.

This functionality has been built as a custom solution on top of SAP Hybris Marketing. In case of any questions, don’t hesitate to contact me.

To report this post you need to login first.


You must be Logged on to comment or reply to a post.

    1. Tim Nusch Post author

      Hi @Krish,

      I have updated the blog post and added some coding examples. In context of this custom solution, a new OData service has been developed. The URL has to point to the service on the customer webservice.

      In case of additional questions, don’t hesitate to contact me.


  1. Vervinckt Joyca

    Thank you, this is very interesting!

    I think SAP should include this in the roadmap for hybris marketing to build it into the solution. This is a functionality that almost all other marketing automation tools offer.



  2. Saurabh Shrivastava

    Hi Tim,

    Thanks for this blog.

    I followed your blog and created a ODATA service ( using SAP gateway service builder).

    The entity type is having two parameters i.e. “OutboundID’ ( key) and “EmailHtml”.

    I have added following URL in email.

    Also redefined the “GET_ENTITYSET” method and added logic to get the email content ID and related email.

    However the problem I am facing is the following –

    1. The table “IT_KEY_TAB” is blank. I am not sure how to pass the outbound ID  to the ODATA service parameter   “OutboundID’. Am I missing anything here?
    2. lv_path = me->get_tracking_path( ). Please let me know what is this path referring, how to get this path. It seems this method is a custom method.

    Following is the metadata –

    <edmx:Edmx Version=”1.0″><edmx:DataServices m:DataServiceVersion=”2.0″><Schema Namespace=”ZMKT_EMAIL_ODATA_SRV” xml:lang=”en” sap:schema-version=”1″><EntityType Name=”EMAIL_ODATA” sap:content-version=”1″><Key><PropertyRef Name=”OutboundId”/></Key><Property Name=”OutboundId” Type=”Edm.Binary” Nullable=”false” sap:label=”NodeID” sap:creatable=”false” sap:updatable=”false” sap:sortable=”false” sap:filterable=”false”/><Property Name=”EmailHtml” Type=”Edm.String” Nullable=”false” sap:label=”EMAIL_HTML” sap:creatable=”false” sap:updatable=”false” sap:sortable=”false” sap:filterable=”false”/></EntityType><EntityContainer Name=”ZMKT_EMAIL_ODATA_SRV_Entities” m:IsDefaultEntityContainer=”true” sap:supported-formats=”atom json xlsx”><EntitySet Name=”EMAIL_ODATASet” EntityType=”ZMKT_EMAIL_ODATA_SRV.EMAIL_ODATA” sap:creatable=”false” sap:updatable=”false” sap:deletable=”false” sap:pageable=”false” sap:content-version=”1″/></EntityContainer><atom:link rel=”self” href=”http://XXXXXX/sap/opu/odata/sap/zmkt_email_odata_srv/$metadata”/><atom:link rel=”latest-version” href=”http://XXXXXXX/sap/opu/odata/sap/zmkt_email_odata_srv/$metadata”/></Schema></edmx:DataServices></edmx:Edmx>

    Following code in “GET_ENTITYSET” –


    METHOD email_odataset_get_entityset.

    DATA: ls_entityset   TYPE zcl_zmkt_email_odata_mpc=>ts_email_odata,
    lv_outbound_id TYPE /bobf/conf_key,
    it_source_key  TYPE /iwbep/t_mgw_tech_pairs,
    lv_content_id  TYPE cuan_me_engagement_id,
    lv_email       TYPE string.

    FIELD-SYMBOLS: <ls_key_outbound_id>      TYPE /iwbep/s_mgw_name_value_pair.
    FIELD-SYMBOLS: <ls_source_key> TYPE /iwbep/s_mgw_tech_pair.

    CONSTANTS : co_outbound_id TYPE string VALUE ‘OUTBOUND_ID’.

    * * find Outbound key
    READ TABLE it_key_tab ASSIGNING <ls_key_outbound_id> WITH KEY name = co_outbound_id.
    IF sy-subrc = 0.
    lv_outbound_id = <ls_key_outbound_id>-value.
    it_source_key           = io_tech_request_context->get_source_keys( ).
    READ TABLE it_source_key WITH KEY name = ‘OUTBOUND_ID’ ASSIGNING <ls_source_key>.
    IF sy-subrc = 0.
    lv_outbound_id = <ls_key_outbound_id>-value.
    *Get content ID
    IF lv_outbound_id IS NOT INITIAL.
    lv_content_id = me->get_content_id( EXPORTING iv_exec_hash =  lv_outbound_id ).
    *Get email
    lv_email = me->get_html_content( EXPORTING iv_content_id = lv_content_id ).
    *Update entity set
    IF lv_email IS NOT INITIAL.
    ls_entityset-email_html = lv_email.
    ls_entityset-outbound_id = lv_outbound_id.
    APPEND ls_entityset TO et_entityset.






    1. Tim Nusch Post author

      Hi Debashis,

      1. I used GET_ENTITY instead of GET_ENTITYSET and passed the outbound id like this:
        EMAIL_ODATASet(‘BE32914DBEKD’), BE32914DBEKD being the outbound id.
        Within GET_ENTITY you can then access the URL parameters like this:
        lt_parameters = io_tech_request_context->get_keys( ).
        READ TABLE lt_parameters WITH KEY name = 'OUTBOUND_ID' INTO ls_parameters.​
      2. For get_tracking_path I mainly used the logic from

        CL_CUAN_MKT_EXEC_EXECUTE_EMAIL->GET_TRACKING_PATH. I needed to do some customer-specific logic, that is why I added an own GET_TRACKING_PATH method to the class. 

      I hope this helps!

      Best regards,



Leave a Reply