Skip to Content
SAP Marketing

How To Connect Your Own Email Service Provider to SAP Hybris Marketing (IV) - SendGrid Adapter Class Implementation

Tags:

Appendix: SendGrid Adapter Class Implementation

In this document, you find the complete coding for the SendGrid example adapter class implementation:

CLASS zcl_cuan_mkt_exec_email_sg DEFINITION

  PUBLIC

  INHERITING FROM cl_cuan_mkt_exec_email

  CREATE PUBLIC .

  PUBLIC SECTION.

    METHODS constructor

      IMPORTING

        !it_parameters TYPE cuan_t_mkt_exec_param .

    METHODS if_cuan_mkt_exec_bounce~bounces_pull

        REDEFINITION .

    METHODS if_cuan_mkt_exec_bounce~get_bounce_collection_mode

        REDEFINITION .

    METHODS if_cuan_mkt_exec_email~retrieve_verified_senders

        REDEFINITION .

    METHODS if_cuan_mkt_exec_http_outbound~build_request

        REDEFINITION .

    METHODS if_cuan_mkt_exec_http_outbound~check_connection

        REDEFINITION .

    METHODS if_cuan_mkt_exec_http_outbound~get_parameters

        REDEFINITION .

    METHODS if_cuan_mkt_exec_http_outbound~process_response

        REDEFINITION .

  PROTECTED SECTION.

  PRIVATE SECTION.

    DATA mv_bounce_destination TYPE rfcdest .

    DATA mv_provider TYPE cuan_me_provider_id .

    DATA mv_api_key TYPE string .

ENDCLASS.

CLASS zcl_cuan_mkt_exec_email_sg IMPLEMENTATION.

  METHOD constructor.

       super->constructor( it_parameters = it_parameters ).

    DATA(lt_parameters) = it_parameters.

    IF lt_parameters IS INITIAL.

         lt_parameters = me->if_cuan_mkt_exec_http_outbound~get_parameters( ).

    ENDIF.

*   get SendGrid API key

    READ TABLE lt_parameters ASSIGNING FIELD-SYMBOL(<ls_api_key>) WITH KEY param_name = 'API_KEY'.

    IF sy-subrc = 0.

         me->mv_api_key = <ls_api_key>-param_value.

    ENDIF.

 

  ENDMETHOD.

  METHOD if_cuan_mkt_exec_http_outbound~get_parameters.

    APPEND VALUE #( param_name = 'API_KEY'

                                     param_value = <your API key here> )

           TO rt_parameters.

  ENDMETHOD.

  METHOD if_cuan_mkt_exec_http_outbound~build_request.

*   Set HTTP verb to POST

       io_request->set_method( io_request->co_request_method_post ).

    DATA lt_header TYPE tihttpnvp.

    DATA ls_header_field TYPE ihttpnvp.

*   Specify the HTTP header fields

       ls_header_field-name = 'Authorization' ##NO_TEXT.

       ls_header_field-value = |Bearer | && me->mv_api_key.

    APPEND ls_header_field TO lt_header.

       ls_header_field-name = 'Content-Type' ##NO_TEXT.

       ls_header_field-value = 'application/json'.

    APPEND ls_header_field TO lt_header.

       io_request->set_header_fields( lt_header ).

*   encode hyphens

    REPLACE ALL OCCURRENCES OF '"' IN me->mv_body_html WITH '\"'.

*   build the HTTP payload

    DATA(lv_body)  = '{"personalizations": [{"to": [{"email": "' && me->mv_recipient && '" } ] } ] ,' &&

                     '"from": {"email": "' && me->mv_sender && '"},' &&

                     '"subject": "' && me->mv_subject && '",' &&

                     '"content": [' &&                    

                     '{"type": "text/html", "value": "' && me->mv_body_html && '"}],' &&

                     '"tracking_settings": { "open_tracking": { "enable": false } } }'.

      io_request->set_cdata( EXPORTING data   =  lv_body ).

  ENDMETHOD.

  METHOD if_cuan_mkt_exec_http_outbound~process_response.

    DATA: lv_http_code TYPE i.

    DATA: lv_reason TYPE string.

    DATA: lv_type TYPE string.

    DATA: lv_code TYPE string.

    DATA: lv_message TYPE string.

    DATA: lv_cdata TYPE string.

    DATA: lt_headers  TYPE tihttpnvp.

    CLEAR es_member_status.

       io_response->get_status( IMPORTING  code   = lv_http_code

                                                                         reason = lv_reason ).

       lv_cdata = io_response->get_cdata( ).

       io_response->get_header_fields( CHANGING fields = lt_headers ).

    CASE lv_http_code.

      WHEN 202. "Successful request -> prepare EMAIL_OUTBOUND interaction

               es_member_status-ia_type = if_cuan_mkt_exec_c=>c_ia_email_outbound.

        READ TABLE lt_headers ASSIGNING FIELD-SYMBOL(<ls_header>) WITH KEY name = 'x-message-id'.

        IF sy-subrc <> 0.

*         no outbound id in success case -> fatal error: STOP sending

          MESSAGE e005(cuan_mkt_exec_frw) INTO lv_message.

                  cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

                  ev_stop_sending = abap_true.

        ENDIF.

              es_member_status-outbound_id = <ls_header>-value.

      WHEN OTHERS. "Error -> Stop sending

        MESSAGE e004(cuan_mkt_exec_frw) INTO lv_message WITH lv_http_code lv_reason lv_cdata.

              cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

              ev_stop_sending = abap_true.

    ENDCASE.

  ENDMETHOD.

  METHOD if_cuan_mkt_exec_bounce~get_bounce_collection_mode.

*   Set bounce collection mode to PULL

    rv_mode = if_cuan_mkt_exec_bounce=>c_bounce_mode_pull.

  ENDMETHOD.

  METHOD if_cuan_mkt_exec_bounce~bounces_pull.

    DATA: lo_client         TYPE REF TO if_http_client.

    DATA: lv_messages_count TYPE i VALUE 0.

       me->mv_bounce_destination = iv_destination.

*   open bounce RFC destination

      cl_http_client=>create_by_destination( EXPORTING destination = me->mv_bounce_destination

                                          IMPORTING client = lo_client

                                          EXCEPTIONS OTHERS = 1 ).

    IF sy-subrc <> 0.

      MESSAGE e000(cuan_mkt_exec_frw) INTO DATA(lv_message) WITH me->mv_bounce_destination.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

      RETURN.

    ENDIF.

*   get unix timestamp

    DATA: lv_end_time TYPE i.

    CALL 'ALERTS' ID 'ADMODE'         FIELD 20

                  ID 'OPCODE'         FIELD 30

                  ID 'ACT_TIME'       FIELD lv_end_time.

*   build GET request

    DATA(lv_start_time) = lv_end_time - 86400. " collect bounces of one day

       lo_client->request->set_method( lo_client->request->co_request_method_get ).

    DATA(lv_request_id) = |?start_time=| && lv_start_time

                        && |&end_time=| && lv_end_time.

       lo_client->request->set_header_field( name = '~request_uri' value = lv_request_id ).

    DATA lt_header TYPE tihttpnvp.

    DATA ls_header_field TYPE ihttpnvp.

       ls_header_field-name = 'Authorization'.

       ls_header_field-value = |Bearer | && me->mv_api_key.

    APPEND ls_header_field TO lt_header.

       ls_header_field-name = 'Content-Type'.

       ls_header_field-value = 'application/json'.

    APPEND ls_header_field TO lt_header.

       ls_header_field-name = 'Accept'.

       ls_header_field-value = 'application/json'.

    APPEND ls_header_field TO lt_header.

       lo_client->request->set_header_fields( lt_header ).

*   send HTTP request

       lo_client->send( EXCEPTIONS OTHERS = 1 ).

    IF sy-subrc <> 0.

           lo_client->get_last_error( IMPORTING message = DATA(lv_error_message)  ).

      MESSAGE e002(cuan_mkt_exec_frw) WITH lv_error_message INTO lv_message.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

      RETURN.

    ENDIF.

       lo_client->receive( EXCEPTIONS http_communication_failure = 1

                                                                http_invalid_state         = 2

                                                                http_processing_failed     = 3

                                   OTHERS                     = 4 ).

    IF sy-subrc <> 0.

           lo_client->get_last_error( IMPORTING message = lv_error_message ).

      MESSAGE e002(cuan_mkt_exec_frw) WITH lv_error_message INTO lv_message.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

      RETURN.

    ENDIF.

*   process HTTP response

       lo_client->response->get_status( IMPORTING  code   = DATA(lv_http_code)

                                                                                       reason = DATA(lv_reason)  ).

    DATA(lv_cdata) = lo_client->response->get_cdata( ).

    IF lv_http_code <> 200.

      MESSAGE e004(cuan_mkt_exec_frw) WITH lv_http_code lv_reason lv_cdata  INTO lv_message.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

      RETURN.

    ENDIF.

*   close RFC destionation

       lo_client->close( EXCEPTIONS OTHERS = 1 ).

    IF sy-subrc <> 0.

      MESSAGE e003(cuan_mkt_exec_frw) INTO lv_message.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

    ENDIF.

*   process bounce payload (find email outbound IAs, create bounce IAs etc.) and deleted from queue

*   get all bounced email adresses

    FIND ALL OCCURRENCES OF REGEX '\"email\":\"([A-Za-z0-9_\-@.]+)\"' IN lv_cdata RESULTS DATA(lt_results).

    DATA lt_bounces TYPE STANDARD TABLE OF string.

    LOOP AT lt_results ASSIGNING FIELD-SYMBOL(<fs_result_tab>).

      DATA(lv_offset) = <fs_result_tab>-offset + 9.

      DATA(lv_length) = <fs_result_tab>-length - 10.

      DATA(lv_message_part) = lv_cdata+lv_offset(lv_length).

      APPEND lv_message_part TO lt_bounces.

    ENDLOOP.

*   retrieve all outbound hashes of EMAIL_OUTBOUND interactions with the bounced adresses of today

    IF lt_bounces IS NOT INITIAL.

      DATA lt_outbound_hashes TYPE STANDARD TABLE OF hpa_generic_object_id.

      SELECT source_object_id FROM cuand_ce_ia_rt FOR ALL ENTRIES IN @lt_bounces

              WHERE id = @lt_bounces-table_line

                    AND ia_date = @sy-datum

                    AND ia_type = 'EMAIL_OUTBOUND'

                    AND id_origin = 'EMAIL'

                    AND execution_run_key <> '00000000000000000000000000000000'

                    AND comm_medium = 'EMAIL'

                    AND source_object_type = 'CUAN_MARKETING_ORCHESTRATION'

              INTO TABLE @lt_outbound_hashes.

    ENDIF.

*   retrieve corresponding outbound IDs

    IF lt_outbound_hashes IS NOT INITIAL.

      DATA lt_outbound_exec_hashes TYPE STANDARD TABLE OF cuan_mkt_exec_hash.

      DATA lt_outbound_ids TYPE STANDARD TABLE OF cuan_mkt_exec_outbound_id.

      LOOP AT lt_outbound_hashes ASSIGNING FIELD-SYMBOL(<lv_outbound_hash>).

        APPEND <lv_outbound_hash> TO lt_outbound_exec_hashes.

      ENDLOOP.

      SELECT outbound_id FROM cuand_exec_hash FOR ALL ENTRIES IN @lt_outbound_exec_hashes

             WHERE personalization_hash = @lt_outbound_exec_hashes-table_line

             INTO TABLE @lt_outbound_ids.

    ENDIF.

*   prepare hard bounces for all bounced email adresses

    DATA: ls_bounce_interaction  TYPE cuan_s_mkt_exec_member_status.

    DATA: lt_bounce_interactions TYPE cuan_t_mkt_exec_member_status.

    LOOP AT lt_outbound_ids ASSIGNING FIELD-SYMBOL(<lv_outbound_id>).

      CLEAR ls_bounce_interaction.

           ls_bounce_interaction = VALUE #( ia_type     = if_cuan_mkt_exec_c=>c_ia_email_bounce_hard

                                                                        outbound_id = <lv_outbound_id> ).

      APPEND ls_bounce_interaction TO lt_bounce_interactions.

    ENDLOOP.

*   update the interactions: remove EMAIL_OUTBOUND and create corresponding EMAIL_BOUNCE_HARD interactions

    cl_cuan_mkt_exec_bounces=>update_interactions_bounces( EXPORTING it_bounce_interactions = lt_bounce_interactions

                                                         IMPORTING et_messages            = DATA(lt_messages)

                                                                                                                           ev_error               = DATA(lv_interactions_error) ).

    APPEND LINES OF lt_messages TO et_messages.

*   Delete bounces from SendGrid queue

    cl_http_client=>create_by_destination( EXPORTING destination = me->mv_bounce_destination

                                         IMPORTING client = lo_client

                                         EXCEPTIONS OTHERS = 1 ).

    IF sy-subrc <> 0.

      MESSAGE e000(cuan_mkt_exec_frw) INTO lv_message WITH me->mv_bounce_destination.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

      RETURN.

    ENDIF.

    lo_client->request->set_method( 'DELETE' ).

    CLEAR ls_header_field.

    REFRESH lt_header.

       ls_header_field-name = 'Authorization' ##NO_TEXT.

       ls_header_field-value = |Bearer | && me->mv_api_key.

    APPEND ls_header_field TO lt_header.

       ls_header_field-name = 'Content-Type' ##NO_TEXT.

       ls_header_field-value = 'application/json'.

    APPEND ls_header_field TO lt_header.

       ls_header_field-name = 'Accept' ##NO_TEXT.

       ls_header_field-value = 'application/json'.

    APPEND ls_header_field TO lt_header.

       lo_client->request->set_header_field( name = '~request_uri' value = '' ).

       lo_client->request->set_cdata( data = '{ "delete_all": true }' ).

       lo_client->request->set_header_fields( lt_header ).

       lo_client->send( EXCEPTIONS OTHERS = 1 ).

    IF sy-subrc <> 0.

           lo_client->get_last_error( IMPORTING message = lv_error_message  ).

      MESSAGE e002(cuan_mkt_exec_frw) WITH lv_error_message INTO lv_message.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

      RETURN.

    ENDIF.

       lo_client->receive( EXCEPTIONS http_communication_failure = 1

                                                                http_invalid_state         = 2

                                                                http_processing_failed     = 3

                                   OTHERS                     = 4 ).

    IF sy-subrc <> 0.

          lo_client->get_last_error( IMPORTING message = lv_error_message ).

      MESSAGE e002(cuan_mkt_exec_frw) WITH lv_error_message INTO lv_message.

          cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

      RETURN.

    ENDIF.

       lo_client->response->get_status( IMPORTING  code   = lv_http_code

                                                                                        reason = lv_reason  ).

    IF lv_http_code <> 204.

      MESSAGE e004(cuan_mkt_exec_frw) WITH lv_http_code lv_reason lv_cdata  INTO lv_message.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

      RETURN.

    ENDIF.

       lo_client->close( EXCEPTIONS OTHERS = 1 ).

    IF sy-subrc <> 0.

      MESSAGE e003(cuan_mkt_exec_frw) INTO lv_message.

           cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

    ENDIF.

    IF lv_interactions_error IS NOT INITIAL.

      RETURN.

    ENDIF.

    DESCRIBE TABLE lt_bounce_interactions LINES DATA(lv_lines).

    MESSAGE s025(cuan_mkt_exec_frw) WITH lv_lines  INTO lv_message.

       cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

  ENDMETHOD.

  METHOD if_cuan_mkt_exec_email~retrieve_verified_senders.

*   specify verified domain

    APPEND <your domain here> TO et_domains.

  ENDMETHOD.

  METHOD if_cuan_mkt_exec_http_outbound~check_connection.

    ev_success = abap_false.

    IF iv_connection_type = if_cuan_mkt_exec_c=>c_connection_check_send

     OR iv_connection_type = if_cuan_mkt_exec_c=>c_connection_check_bounce.

*     the expected response when pinging the SendGrid API is an 405 HTTP code and a reason 'Method Not Allowed'

      IF iv_http_code <> 405 OR iv_reason <> 'Method Not Allowed'.

        MESSAGE e002(cuan_mkt_exec_frw) WITH iv_http_code && ' ' && iv_reason INTO DATA(lv_message).

               cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

        RETURN.

      ENDIF.

    ENDIF.

  ENDMETHOD.

ENDCLASS.

Former Member