Sending a report or spool job by email
This post inaugurates a new category in Abapinho: Code. Posts in this category will present useful programs that are ready to execute.
This one is used for sending the result of any report or spool order by e-mail. This program makes use of the new BCS (Business Communication Services) through the CL_BCS class instead of the tired and old SO_DOCUMENT_SEND_API1, may its soul rest in peace.
The content can be sent in the body of the email, as a TXT attachment or as an HTML attachment, with the latter being sent nice and neat with all the colours. Enjoy it. Blindly copy it and use it or dissect it and learn how to use CL_BCS. On the way, you can still learn, if you feel like it, how to use local classes and exception classes.
A local class is simpler to show here in Abapinho but if you want you can transform it into a global class through SE24 as Abapinho already explained some time ago so that you can use it anywhere.
*&---------------------------------------------------------------------*
*& Report ZZZ_NFG_SEND_REPORT_BY_EMAIL
*&
*&---------------------------------------------------------------------*
*& Author: Nuno Godinho
*& Date: 03 January 2012
*& Description: Sends an abap list (generated by a submitted program or
*& read from an existing spool) by email. The list can be
*& sent either in the email body, as a text attachment or
*& as an HTML attachment.
*&---------------------------------------------------------------------*
REPORT zzz_nfg_send_list_by_mail MESSAGE-ID so.
***************************************************************************
* Exception classes
CLASS zcx_zs_no_receivers
DEFINITION FINAL INHERITING FROM cx_static_check.
ENDCLASS.
CLASS zcx_zs_spool_error
DEFINITION FINAL INHERITING FROM cx_static_check.
ENDCLASS.
CLASS zcx_zs_invalid_parameters
DEFINITION FINAL INHERITING FROM cx_static_check.
ENDCLASS.
CLASS zcx_zs_objectlist_error
DEFINITION FINAL INHERITING FROM cx_static_check.
ENDCLASS.
*----------------------------------------------------------------------*
* CLASS cl_send_list_by_mail DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS cl_send_list_by_mail DEFINITION.
PUBLIC SECTION.
TYPES: ty_send_mode TYPE char4,
ty_source TYPE char6.
CONSTANTS:
k_send_mode_text TYPE ty_send_mode VALUE 'TEXT',
k_send_mode_text_attach TYPE ty_send_mode VALUE 'TXTA',
k_send_mode_html_attach TYPE ty_send_mode VALUE 'HTMA',
k_send_mode_attachment TYPE ty_send_mode VALUE space,
k_source_submit TYPE ty_source VALUE 'SUBMIT',
k_source_spool TYPE ty_source VALUE 'SPOOL'.
METHODS:
constructor
RAISING
cx_send_req_bcs,
add_recipient
IMPORTING
i_smtp_address TYPE ad_smtpadr
RAISING
cx_send_req_bcs
cx_address_bcs,
submit_and_send_mail
IMPORTING
i_report TYPE program
i_variant TYPE raldb_vari
i_send_mode TYPE ty_send_mode
i_subject TYPE so_obj_des
i_smtp_address TYPE ad_smtpadr OPTIONAL
RAISING
zcx_zs_no_receivers
cx_bcs
zcx_zs_invalid_parameters
zcx_zs_objectlist_error
zcx_zs_spool_error,
read_spool_and_send_mail
IMPORTING
i_spool_number TYPE rspoid
i_send_mode TYPE ty_send_mode
i_subject TYPE so_obj_des
i_smtp_address TYPE ad_smtpadr OPTIONAL
RAISING
zcx_zs_no_receivers
zcx_zs_invalid_parameters
zcx_zs_objectlist_error
cx_send_req_bcs
cx_bcs
zcx_zs_spool_error.
PRIVATE SECTION.
DATA: go_send_request TYPE REF TO cl_bcs.
METHODS:
get_objectlist_and_send_mail
IMPORTING
i_source TYPE ty_source
i_report TYPE program OPTIONAL
i_variant TYPE raldb_vari OPTIONAL
i_spool_number TYPE rspoid OPTIONAL
i_send_mode TYPE ty_send_mode
i_subject TYPE so_obj_des
i_smtp_address TYPE ad_smtpadr OPTIONAL
RAISING
zcx_zs_no_receivers
zcx_zs_invalid_parameters
zcx_zs_objectlist_error
cx_bcs
zcx_zs_spool_error,
submit_report_to_memory
IMPORTING
value(i_report) TYPE program
value(i_variant) TYPE raldb_vari
RETURNING
value(ot_listobject) TYPE table_abaplist
RAISING
zcx_zs_objectlist_error,
read_spool_to_memory
IMPORTING
i_spool_number TYPE rspoid
RETURNING
value(ot_listobject) TYPE table_abaplist
RAISING
zcx_zs_spool_error,
get_objectlist
IMPORTING
i_source TYPE ty_source
value(i_report) TYPE program
value(i_variant) TYPE raldb_vari
i_spool_number TYPE rspoid
RETURNING
value(ot_listobject) TYPE table_abaplist
RAISING
zcx_zs_spool_error
zcx_zs_objectlist_error,
create_text_document
IMPORTING
i_report TYPE program
i_variant TYPE raldb_vari
i_spool_number TYPE rspoid
i_subject TYPE so_obj_des
it_listobject TYPE table_abaplist OPTIONAL
RETURNING
value(o_document) TYPE REF TO cl_document_bcs
RAISING
zcx_zs_objectlist_error
cx_document_bcs,
add_header_to_body
IMPORTING
i_report TYPE program
i_variant TYPE raldb_vari
i_spool_number TYPE rspoid
CHANGING
xt_soli TYPE soli_tab,
add_abaplist_text_attach
IMPORTING
it_listobject TYPE table_abaplist
i_name TYPE so_obj_des
CHANGING
x_document TYPE REF TO cl_document_bcs
RAISING
zcx_zs_objectlist_error
cx_document_bcs,
add_abaplist_html_attach
IMPORTING
it_listobject TYPE table_abaplist
i_name TYPE so_obj_des
CHANGING
x_document TYPE REF TO cl_document_bcs
RAISING
cx_document_bcs,
send_mail
IMPORTING
value(it_listobject) TYPE table_abaplist
i_report TYPE program OPTIONAL
i_variant TYPE raldb_vari OPTIONAL
i_spool_number TYPE rspoid OPTIONAL
i_send_mode TYPE ty_send_mode
i_subject TYPE so_obj_des
RAISING
zcx_zs_objectlist_error
zcx_zs_invalid_parameters
cx_bcs,
build_attach_name
IMPORTING
i_report TYPE program
i_variant TYPE raldb_vari
i_spool_number TYPE rspoid
i_extension TYPE so_obj_des OPTIONAL
RETURNING value(o_name) TYPE so_obj_des.
ENDCLASS. "cl_send_list_by_mail DEFINITION
*----------------------------------------------------------------------*
* CLASS cl_send_list_by_mail IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS cl_send_list_by_mail IMPLEMENTATION.
METHOD constructor.
* Create the send request
go_send_request = cl_bcs=>create_persistent( ).
go_send_request->set_send_immediately( 'X' ).
ENDMETHOD. "constructor
METHOD add_recipient.
DATA: recipient TYPE REF TO if_recipient_bcs.
recipient = cl_cam_address_bcs=>create_internet_address( i_smtp_address ).
go_send_request->add_recipient( recipient ).
ENDMETHOD. "add_receiver
METHOD submit_and_send_mail.
get_objectlist_and_send_mail(
i_source = k_source_submit
i_send_mode = i_send_mode
i_report = i_report
i_variant = i_variant
i_subject = i_subject ).
ENDMETHOD. "submit_report_and_sendmail
METHOD read_spool_and_send_mail.
get_objectlist_and_send_mail(
i_source = k_source_spool
i_send_mode = i_send_mode
i_spool_number = i_spool_number
i_subject = i_subject ).
ENDMETHOD. "read_spool_and_send_mail
METHOD get_objectlist_and_send_mail.
DATA: t_recipients TYPE bcsy_re,
t_listobject TYPE table_abaplist.
* Check parameters
IF ( i_source = k_source_spool AND i_spool_number IS INITIAL ) OR
( i_source = k_source_submit AND i_report IS INITIAL ).
RAISE EXCEPTION TYPE zcx_zs_invalid_parameters.
ENDIF.
* Add recipient if supplied
IF i_smtp_address IS SUPPLIED.
add_recipient( i_smtp_address ).
ENDIF.
* It should only run if there is at least one recipient
t_recipients = go_send_request->recipients( ).
IF t_recipients[] IS INITIAL.
RAISE EXCEPTION TYPE zcx_zs_no_receivers.
ENDIF.
* Get objectlist either from submit or from spool
t_listobject = get_objectlist(
i_source = i_source
i_report = i_report
i_variant = i_variant
i_spool_number = i_spool_number ).
* Send email
CALL METHOD send_mail
EXPORTING
it_listobject = t_listobject
i_report = i_report
i_variant = i_variant
i_spool_number = i_spool_number
i_send_mode = i_send_mode
i_subject = i_subject.
ENDMETHOD. "get_objectlist_and_send_mail
METHOD get_objectlist.
* Get abap list into memory (either from spool or submit)
IF i_source = k_source_submit.
submit_report_to_memory( i_report = i_report i_variant = i_variant ).
ELSE.
read_spool_to_memory( i_spool_number = i_spool_number ).
ENDIF.
* Import the list from memory and store it in table listobject
REFRESH : ot_listobject.
CALL FUNCTION 'LIST_FROM_MEMORY'
TABLES
listobject = ot_listobject
EXCEPTIONS
not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE zcx_zs_objectlist_error.
ENDIF.
* Free memory
CALL FUNCTION 'LIST_FREE_MEMORY'
TABLES
listobject = ot_listobject
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE zcx_zs_objectlist_error.
ENDIF.
ENDMETHOD. "get_objectlist
METHOD submit_report_to_memory.
TRANSLATE: i_report TO UPPER CASE,
i_variant TO UPPER CASE.
* Submit report
SUBMIT (i_report) USING SELECTION-SET i_variant EXPORTING LIST TO MEMORY AND RETURN.
ENDMETHOD. "submit_report
METHOD read_spool_to_memory.
* Adapted from FM RSPO_RETURN_ABAP_SPOOLJOB. This FM converts the list to ASCII
* and I needed it as an ABAPLIST so I just copied the code and adapted it
DATA: data_is_otf TYPE c.
CALL FUNCTION 'RSPO_CHECK_JOB_ID_PERMISSION'
EXPORTING
rqident = i_spool_number
access = 'DISP'
EXCEPTIONS
no_such_job = 1
no_permission = 2.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE zcx_zs_spool_error.
ENDIF.
CALL FUNCTION 'RSPO_GET_TYPE_SPOOLJOB'
EXPORTING
rqident = i_spool_number
IMPORTING
is_otf = data_is_otf
EXCEPTIONS
can_not_access = 1.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE zcx_zs_spool_error.
ENDIF.
IF data_is_otf = 'X'.
RAISE EXCEPTION TYPE zcx_zs_spool_error.
ELSE.
SUBMIT rspolist EXPORTING LIST TO MEMORY AND RETURN
WITH rqident = i_spool_number
WITH first = 1
WITH last = 0
WITH pages = space.
ENDIF.
ENDMETHOD. "read_spool
METHOD send_mail.
DATA: document TYPE REF TO cl_document_bcs,
sent_to_all TYPE os_boolean,
bcs_exception TYPE REF TO cx_bcs,
name TYPE so_obj_des.
IF i_send_mode = k_send_mode_text.
document = create_text_document(
i_report = i_report
i_variant = i_variant
i_spool_number = i_spool_number
it_listobject = it_listobject
i_subject = i_subject ).
ELSE.
* Create text document without adding listobject to the body (it will be attached)
document = create_text_document(
i_report = i_report
i_variant = i_variant
i_spool_number = i_spool_number
i_subject = i_subject ).
* Add attachment to document
IF i_send_mode = k_send_mode_text_attach.
name = build_attach_name(
i_report = i_report
i_variant = i_variant
i_spool_number = i_spool_number
i_extension = 'TXT' ).
add_abaplist_text_attach(
EXPORTING
it_listobject = it_listobject
i_name = name
CHANGING
x_document = document ).
ELSEIF i_send_mode = k_send_mode_html_attach.
name = build_attach_name(
i_report = i_report
i_variant = i_variant
i_spool_number = i_spool_number ).
add_abaplist_html_attach(
EXPORTING
it_listobject = it_listobject
i_name = name
CHANGING
x_document = document ).
ENDIF.
ENDIF.
* Add document to send request
go_send_request->set_document( document ).
* Send
sent_to_all = go_send_request->send( i_with_error_screen = 'X' ).
* IF sent_to_all NE 'X'.
* RAISE EXCEPTION TYPE zcx_zs_mail_not_sent.
* ENDIF.
ENDMETHOD. "send_mail
METHOD create_text_document.
DATA: t_listasci TYPE STANDARD TABLE OF solisti1,
t_listobject LIKE it_listobject,
t_soli TYPE soli_tab,
w_soli LIKE LINE OF t_soli.
* Add header
add_header_to_body(
EXPORTING
i_report = i_report
i_variant = i_variant
i_spool_number = i_spool_number
CHANGING
xt_soli = t_soli ).
* Add abap list
IF it_listobject IS SUPPLIED.
CLEAR w_soli.
APPEND w_soli TO t_soli.
w_soli = '------------------------------------------------------'.
APPEND w_soli TO t_soli.
CLEAR w_soli.
APPEND w_soli TO t_soli.
t_listobject[] = it_listobject[].
CALL FUNCTION 'LIST_TO_ASCI'
TABLES
listasci = t_listasci
listobject = t_listobject
EXCEPTIONS
empty_list = 1
list_index_invalid = 2
OTHERS = 3.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE zcx_zs_objectlist_error.
ENDIF.
APPEND LINES OF t_listasci TO t_soli.
ENDIF.
* Create text document
o_document = cl_document_bcs=>create_document(
i_type = 'RAW'
i_text = t_soli
i_subject = i_subject ).
ENDMETHOD. "create_text_document
METHOD add_header_to_body.
DATA: w_soli LIKE LINE OF xt_soli.
IF i_report IS NOT INITIAL.
CONCATENATE 'Report:' i_report INTO w_soli SEPARATED BY space.
APPEND w_soli TO xt_soli.
ENDIF.
IF i_variant IS NOT INITIAL.
CONCATENATE 'Variant:' i_variant INTO w_soli SEPARATED BY space.
APPEND w_soli TO xt_soli.
ENDIF.
IF i_spool_number IS NOT INITIAL.
MOVE i_spool_number TO w_soli.
CONCATENATE 'Spool number:' w_soli INTO w_soli SEPARATED BY space.
APPEND w_soli TO xt_soli.
ENDIF.
CONCATENATE 'Date:' sy-datum sy-uzeit INTO w_soli SEPARATED BY space.
APPEND w_soli TO xt_soli.
CONCATENATE 'User:' sy-uname INTO w_soli SEPARATED BY space.
APPEND w_soli TO xt_soli.
ENDMETHOD. "build_header
METHOD add_abaplist_text_attach.
DATA: t_solix TYPE solix_tab.
* It's always necessary to compress the table. SAPconnect will decompress it
CALL FUNCTION 'TABLE_COMPRESS' "#EC *
TABLES
in = it_listobject
out = t_solix
EXCEPTIONS
compress_error = 1
OTHERS = 2.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE zcx_zs_objectlist_error.
ENDIF.
x_document->add_attachment(
i_attachment_type = 'ALI'
i_attachment_subject = i_name
i_att_content_hex = t_solix ).
ENDMETHOD. "add_abaplist_text_attach
METHOD add_abaplist_html_attach.
DATA: t_soli TYPE soli_tab,
t_listobject LIKE it_listobject.
t_listobject[] = it_listobject[].
CALL FUNCTION 'WWW_HTML_FROM_LISTOBJECT'
TABLES
html = t_soli
listobject = t_listobject.
x_document->add_attachment(
i_attachment_type = 'HTM'
i_attachment_subject = i_name
i_att_content_text = t_soli ).
ENDMETHOD. "add_abaplist_html_attach
METHOD build_attach_name.
IF i_report IS NOT INITIAL.
o_name = i_report.
IF i_variant IS NOT INITIAL.
CONCATENATE o_name '-' i_variant INTO o_name.
ENDIF.
ELSE.
MOVE i_spool_number TO o_name.
SHIFT o_name LEFT DELETING LEADING space.
ENDIF.
CONCATENATE o_name '-' sy-datum '-' sy-uzeit INTO o_name.
IF i_extension IS NOT INITIAL.
CONCATENATE o_name '.' i_extension INTO o_name.
ENDIF.
ENDMETHOD. "build_attach_name
ENDCLASS. "cl_send_list_by_mail IMPLEMENTATION
***************************************************************************
TABLES: adr6.
*------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
PARAMETERS: p_subj TYPE so_obj_des OBLIGATORY.
SELECT-OPTIONS: s_rec FOR adr6-smtp_addr NO INTERVALS LOWER CASE OBLIGATORY.
SELECTION-SCREEN END OF BLOCK b1.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-002.
PARAMETERS: p_submit RADIOBUTTON GROUP typ USER-COMMAND typ.
SELECTION-SCREEN BEGIN OF BLOCK b2a WITH FRAME.
PARAMETERS: p_rep TYPE program MODIF ID ty1,
p_var TYPE raldb_vari MODIF ID ty1.
SELECTION-SCREEN END OF BLOCK b2a.
PARAMETERS: p_spool RADIOBUTTON GROUP typ.
SELECTION-SCREEN BEGIN OF BLOCK b2b WITH FRAME.
PARAMETERS: p_rspoid TYPE rspoid MODIF ID ty2.
SELECTION-SCREEN END OF BLOCK b2b.
SELECTION-SCREEN END OF BLOCK b2.
SELECTION-SCREEN BEGIN OF BLOCK b3 WITH FRAME TITLE text-003.
PARAMETERS: p_text RADIOBUTTON GROUP opt,
p_texta RADIOBUTTON GROUP opt,
p_htmla RADIOBUTTON GROUP opt DEFAULT 'X'.
SELECTION-SCREEN END OF BLOCK b3.
AT SELECTION-SCREEN OUTPUT.
LOOP AT SCREEN.
IF screen-group1 = 'TY1'.
IF p_submit IS NOT INITIAL.
screen-input = 1.
ELSE.
screen-input = 0.
ENDIF.
MODIFY SCREEN.
ENDIF.
IF screen-group1 = 'TY2'.
IF p_spool IS NOT INITIAL.
screen-input = 1.
ELSE.
screen-input = 0.
ENDIF.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
START-OF-SELECTION.
DATA: go_sender TYPE REF TO cl_send_list_by_mail,
send_mode TYPE cl_send_list_by_mail=>ty_send_mode,
exc_ref TYPE REF TO cx_root,
text TYPE string.
IF ( p_submit IS NOT INITIAL AND p_rep IS INITIAL ) OR
( p_spool IS NOT INITIAL AND p_rspoid IS INITIAL ).
MESSAGE s622 DISPLAY LIKE 'E'.
EXIT.
ENDIF.
CREATE OBJECT go_sender.
* Determine send mode
CASE 'X'.
WHEN p_texta.
send_mode = cl_send_list_by_mail=>k_send_mode_text_attach.
WHEN p_htmla.
send_mode = cl_send_list_by_mail=>k_send_mode_html_attach.
WHEN OTHERS.
send_mode = cl_send_list_by_mail=>k_send_mode_text.
ENDCASE.
* Add recipients
LOOP AT s_rec.
CALL METHOD go_sender->add_recipient
EXPORTING
i_smtp_address = s_rec-low.
ENDLOOP.
TRY.
CASE 'X'.
WHEN p_submit.
CALL METHOD go_sender->submit_and_send_mail
EXPORTING
i_send_mode = send_mode
i_report = p_rep
i_variant = p_var
i_subject = p_subj.
WHEN p_spool.
CALL METHOD go_sender->read_spool_and_send_mail
EXPORTING
i_send_mode = send_mode
i_spool_number = p_rspoid
i_subject = p_subj.
ENDCASE.
WRITE: / 'Mail message sent'.
CATCH cx_root INTO exc_ref.
text = exc_ref->get_text( ).
WRITE: / text.
ENDTRY.
* It will not work without this commit
COMMIT WORK.
Texts for selection screen:
P_SUBJ | Subject |
---|
S_REC| Recipients
P_SUBMIT| Send report
P_REP| Report
P_VAR| Variant
P_SPOOL| Send spool job
P_RSPOID| Spool job ID
P_TEXT| Email body
P_TEXTA| TXT attachment
P_HTMLA| HTML attachment
Greetings from Abapinho.