SAP-Sending Mail With XLSX Attachments Using CL_DOCUMENT_BCS.


Before sending an email, all the required configuration for SMTP and mail server in the SAP server needs to be in place.

Email sending is an existing method of getting the sap job log or report details. People who receive an email in their inbox will do different operations based on the content in it. Email may contain the description alone or with the attached files in it and this is based on the business need.

Sending external email in SAP with attachments like XML, DOC, XLS are the common methodology and now SAP users would like to receive the attachments with XLSX, DOCX - formats as this is the format from MS office 2007. We are going to see in details for how to create XLSX (Generally for four digit file extensions) file attachment and this is the slightly different way than how we do for usual binary XLS attachments in sap external email sending.


Why slightly different approach for XLSX attachment from XLS ?
  • XLSX for versions since 2007 MS office, but, XLS is from 2003.
  • XLSX is only readable by versions 2007 and later XLS is a proprietary binary format while XLSX is based on Office Open XML format.
  • XLSX is not able to support macros while XLS is. We have XLSM extension to support macros from office 2007
  • XLS is based on Binary Interchange File Format, the information is directly stored to a binary format. XLSX is based on the Office Open XML format, a file format that was derived from XML. The information in an XLSX file is stored in a text file that uses XML to define all its parameters.
SAMPLE REQUIREMENT:

Let’s take an example of a business scenario where user needs the report of list of materials which are deletion indicator set at particular plant level. This report is needed to be sent to the responsible person who do analysis and validate its status. Instead of displaying in ALV report or keeping the application server file. User needs this report to be available in his /her email as a XLSX excel attachment report.

DETAIL STEPS:

Below steps will details the procedure you need to follow in your program to send the email with XLSX attachment from ABAP program. Sample program with complete code is attached in additional information section. Based on your business need you can modify the contents in the attached file.

STEP 1:  Declarations Required.

We have to use CL_BCS class based email sending technique, so the first step in this development is to create the instance declarations for required classes / interfaces as below:


CL_BCS is the class which sends the email notification to the group of people assigned as recipient, below code will return the reference of CL_BCS class.

To create the email body CL_DOCUMENT_BCS is used. Below is the way this object reference is created in the program.

STEP 2: Prepare The Final Data To Be Sent In Attachment.

This is the step on which you will be preparing the final table of data. Based on the customer requirement, we need to populate an internal table for attachment file. In this sample program, I have created a structure with Material, Plant-specific material status, purchasing group and profit center.

In the sample code, I have created a select query to read the relevant entries from MARC based on this sample requirement.

We need to prepare the field catalog for internal table we are using. Populate the field catalog as specified in the sample program with the structure of LVC_S_FCAT.

Example of one field provided below:


This field catalog is used to create the header in output XLSX file.

Create the data object reference for the internal table I_LINE as below:

Create the utility class reference as below:

STEP 3: Get XML Version & Prepare The XSTRING Value For Internal Table Entries.

Below is the way to get the current systems XML version and get the XML flavor to be used.


Below step will convert the output attachment data in to XSTRING format based on the XML version and flavors passed.
 Below is the step to convert the XSTRING to binary format, I_OBJ_BIN will have the binary data


STEP 4:  Create File Name & Attachment Object Reference.

Create the file name with XLSX extension (Generally 4 digit extensions), also below logic will provide the user to enter the fee text option while opening the file from email and save in local system.


 Create the attachment document reference and assign it to send request object.

Step 5:  Set Sender & Recipient Details.

Sender object creation is this is necessary only if you want to set the sender different from actual user (SY-UNAME). Otherwise sender is set automatically with actual user.


Recipient can be added in the below way,


STEP 6:  Final Step To Send The Email.

Below instance method will send the email with the attachment and returns the success flag as well. This is the final step in sending the email, next step is the error handling option for any exception occurred.

We need the commit work to be given explicitly for email sending.

STEP 7:  Exception Handling

General BCS exception class can be used for this purpose.


Below is the way to catch the exception and display the error occurred


SAMPLE PROGRAM CODE:

REPORT zl_xlsx_emailsend.
*This report will show the sample of how to send XLSX attachments to email address from sap.

* Types declaration.
TYPES: BEGIN OF ty_line,
         matnr TYPE matnr,"Material Number
         mmsta TYPE mmsta,"Plant-Specific Material Status
         ekgrp TYPE ekgrp,"Purchasing Group
         prctr TYPE prctr,"Profit Center
       END OF ty_line.

*Data declaration
DATA:
       l_version   TYPE string, " Version
       l_flavour   TYPE fpm_file_name, " Flavour
       l_sent_to_all        TYPE os_boolean,
       l_contents_line      TYPE xstring, "vac53733 10642
       l_i                  TYPE sood-objlen,
       l_file_type          TYPE salv_bs_constant,
       l_count TYPE so_obj_len," string length of email body
       l_count1 TYPE i,
       w_line TYPE ty_line. "work area for data table

* Business Communication Service object
DATA: send_request       TYPE REF TO cl_bcs.
* Wrapper Class for Office Documents
DATA: document           TYPE REF TO cl_document_bcs.
* Object Represents an SAP User
DATA: sender             TYPE REF TO cl_sapuser_bcs.
* Interface of Recipient Object in BCS
DATA: recipient          TYPE REF TO if_recipient_bcs.
*BCS: General Exceptions
DATA: bcs_exception      TYPE REF TO cx_bcs.
* Utility Class
DATA: lo_result_data     TYPE REF TO cl_salv_ex_result_data_table.
* Data
DATA: lo_data            TYPE REF TO data.

*Internal table declarations.
DATA: i_fldcat TYPE STANDARD TABLE OF lvc_s_fcat
                 INITIAL SIZE 0, "Field catalog
      i_text               TYPE bcsy_text,   "report internal table
      i_binary_content     TYPE solix_tab,
      i_att_head           TYPE soli_tab,
      i_obj_bin            TYPE solix_tab,  "Binary Internal Table
      l_text_line          TYPE soli,
      l_filename           TYPE string.
DATA: i_line TYPE STANDARD TABLE OF ty_line INITIAL SIZE 0.

* Field symbol declaration.
FIELD-SYMBOLS:      <fs_fieldcat>  TYPE lvc_s_fcat. "Field catalog

* Selection screen parameter

PARAMETERS: p_werks TYPE marc-werks OBLIGATORY.

INITIALIZATION.
  p_werks = 'XXXX'.  "initialize default plant

START-OF-SELECTION.
  PERFORM main.


*---------------------------------------------------------------------*
*       FORM main                                                     *
*---------------------------------------------------------------------*
FORM main.
* Data selection to be sent.

  SELECT matnr "Material Number
         mmsta "Plant-Specific Material Status
         ekgrp "Purchasing Group
         prctr "Profit Center
              FROM marc
              INTO TABLE i_line
              WHERE werks = p_werks AND
                    lvorm = 'X'.

* Preare the fieldcat for output structure.
  APPEND INITIAL LINE TO i_fldcat
    ASSIGNING <fs_fieldcat>.
  <fs_fieldcat>-no_out = ''.            "Hide
  <fs_fieldcat>-fieldname = 'MATNR'.    "Fieldname
  <fs_fieldcat>-outputlen = 18.    "Output length
  <fs_fieldcat>-dd_outlen = 18.     "Input length
  <fs_fieldcat>-reptext   = 'Material Number'.         "Column text
  <fs_fieldcat>-edit      = 'X'.         "Edit
  APPEND INITIAL LINE TO i_fldcat
    ASSIGNING <fs_fieldcat>.
  <fs_fieldcat>-no_out = ''.            "Hide
  <fs_fieldcat>-fieldname = 'MMSTA'.    "Fieldname
  <fs_fieldcat>-outputlen = 2.    "Output length
  <fs_fieldcat>-dd_outlen = 2.     "Input length
  <fs_fieldcat>-reptext   = 'Plant-Specific mat.status'.         "Column text
  <fs_fieldcat>-edit      = 'X'.         "Edit
  APPEND INITIAL LINE TO i_fldcat
    ASSIGNING <fs_fieldcat>.
  <fs_fieldcat>-no_out = ''.            "Hide
  <fs_fieldcat>-fieldname = 'EKGRP'.    "Fieldname
  <fs_fieldcat>-outputlen = 3.    "Output length
  <fs_fieldcat>-dd_outlen = 3.     "Input length
  <fs_fieldcat>-reptext   = 'Purch.group'.         "Column text
  <fs_fieldcat>-edit      = 'X'.         "Edit
  APPEND INITIAL LINE TO i_fldcat
    ASSIGNING <fs_fieldcat>.
  <fs_fieldcat>-no_out = ''.            "Hide
  <fs_fieldcat>-fieldname = 'PRCTR'.    "Fieldname
  <fs_fieldcat>-outputlen = 10.    "Output length
  <fs_fieldcat>-dd_outlen = 10.     "Input length
  <fs_fieldcat>-reptext   = 'Profit center'.         "Column text
  <fs_fieldcat>-edit      = 'X'.         "Edit

  TRY.
*     -------- create persistent send request ------------------------
      send_request = cl_bcs=>create_persistent( ).

      APPEND 'List of materials having deletion flag at plant'(a01) TO i_text.
      APPEND p_werks TO i_text.
      l_count = 255.
*     -------- create and set document with attachment ---------------
      document = cl_document_bcs=>create_document(
                      i_type    = 'RAW'    " Type of data
                      i_text    = i_text     " Email body text
                      i_length  = l_count     " String length of email body
                      i_subject = 'Materials deleted in Plant' ).

* Create data object reference.
      GET REFERENCE OF i_line INTO lo_data.

      CLEAR: lo_result_data.
      lo_result_data =
      cl_salv_ex_util=>factory_result_data_table(
           r_data                      = lo_data " internal table data reference
           t_fieldcatalog              = i_fldcat"field cat
       ).

* get the version from Abstract Super Class for All Transformations
      CLEAR: l_version.
      l_version = cl_salv_bs_a_xml_base=>get_version( ).
* Get the file Type
*     value 10 for XLSX file type
      CLEAR: l_file_type.
      l_file_type = if_salv_bs_xml=>c_type_xlsx.
* Get the flavour export
*      Flavor for Complete ALV XML
      CLEAR: l_flavour.
      l_flavour = if_salv_bs_c_tt=>c_tt_xml_flavour_export.


* Transformation of data to XSTRING
      CLEAR: l_contents_line.
      CALL METHOD cl_salv_bs_tt_util=>if_salv_bs_tt_util~transform
        EXPORTING
          xml_type      = l_file_type
          xml_version   = l_version
          r_result_data = lo_result_data
          xml_flavour   = l_flavour
          gui_type      = if_salv_bs_xml=>c_gui_type_gui
        IMPORTING
          xml           = l_contents_line.


*  Converting the table contents from xstring to binary
      CLEAR i_obj_bin.
      CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
        EXPORTING
          buffer        = l_contents_line
        IMPORTING
          output_length = l_count1
        TABLES
          binary_tab    = i_obj_bin.
      APPEND LINES OF i_obj_bin TO i_binary_content.


* Four character file extension '.XLSX' is set
      l_filename = 'Materialsdeleted.XLSX'. " provide the extension in file name
* You can set a file name with a freely selectable file name extension
* separately from the document description. For this, use the header table
* of the document or the attachment with the key word '&SO_FILENAME='.
      CONCATENATE '&SO_FILENAME='
                  l_filename
                  INTO
                  l_text_line.
      APPEND l_text_line TO i_att_head.

*Calculate the xstring length
      l_i = xstrlen( l_contents_line ).
* Create the attachment reference.
      CALL METHOD document->add_attachment
        EXPORTING
          i_attachment_type    = 'BIN' " type of data
          i_attachment_subject = 'File with deleted materials'
          i_attachment_size    = l_i   " XTRING length of l_contents_line
          i_att_content_hex    = i_binary_content
          i_attachment_header  = i_att_head. "file details

*     add document to send request
      CALL METHOD send_request->set_document( document ).

*     --------- set sender -------------------------------------------
*     note: this is necessary only if you want to set the sender
*           different from actual user (SY-UNAME). Otherwise sender is
*           set automatically with actual user.

"Provide the SAP logon user name to sent the sender (this example user sy-uname)
* You can use uer name as ('VAK10567', etc)
      sender = cl_sapuser_bcs=>create( sy-uname ).
      CALL METHOD send_request->set_sender
        EXPORTING
          i_sender = sender.

*     --------- add recipient (e-mail address) -----------------------
*     create recipient - please replace e-mail address !!!
*     you can create multiple receipient by following this way or
*     you can provide undisclosed recipients list
      recipient = cl_cam_address_bcs=>create_internet_address(
                                        'xxx@yyy.com' ).

*     add recipient with its respective attributes to send request
      CALL METHOD send_request->add_recipient
        EXPORTING
          i_recipient = recipient
          i_express   = 'X'.

*     ---------- send document ---------------------------------------
      CALL METHOD send_request->send(
        EXPORTING
          i_with_error_screen = 'X'
        RECEIVING
          result              = l_sent_to_all ).
      IF l_sent_to_all = 'X'.
        WRITE 'Document Sent Successfully'(098).
      ENDIF.

      COMMIT WORK.

* -----------------------------------------------------------
* *                     Exception Handling
* -----------------------------------------------------------
* * Replace this very rudimentary exception handling
* * With your own one !!!
* -----------------------------------------------------------
    CATCH cx_bcs INTO bcs_exception.
      WRITE: 'Error occured'(001).
      WRITE: 'Error type'(002), bcs_exception->error_type.
      EXIT.
  ENDTRY.

ENDFORM.                    "main