En nuestro truco de hoy inauguramos una sección donde propondremos típicos ejemplos prácticos de necesidad funcional y como solucionarlos, incluyendo en muchos casos elementos de programación Abap.
Empezaremos con un ejemplo clásico donde necesitamos que un report Z envie por email los resultados calculados y que en modo interactivo se muestran en un ALV. Por ejemplo, en una ejecución del programa en fondo queremos que se envíen los resultados a uno o varios usuarios. O incluso el mismo usuario que esta viendo los resultados de forma interactiva quiere enviar la información a otro usuario de la empresa o un contacto externo (cliente o proveedor).
Para nuestro ejemplo, partimos de un desarrollo Z que nos permite listar información de pedidos de compra.

En el informe añadiremos en los criterios de selección del programa añadiremos un campo para poder introducir los destinatarios de email donde queremos enviar los resultados del ALV ( Select-options: so_email for adr6-smtp_addr. )

Y un botón para que el usuario, cuando lo desee, pueda lanzar el envío del correo electrónico que contendrá como anexo una excel con la información.

Ahora, la parte más compleja. La programación necesaria para convertir la tabla interna que estamos utilizando en el ALV en una hoja excel, construir el correo electrónico y enviarlo a los destinatarios.
Básicamente, utilizamos los siguientes elementos de programación:
- Clase cl_salv_bs_tt_util: nos permite convertir una tabla interna a formato excel.
- Clase cl_bcs: para gestionar el envío del correo.
- Clase cl_document_bcs: para crear el correo, indicar asunto y texto, anexar excel, etc.
En mi programa, he creado un FORM que se ejecuta cuando el usuario pulsa el botón de enviar correo, que se llama lanza_envio_mail.
Desde allí se llama a send_email donde se hace todas las operaciones técnicas de convertir la tabla interna a un xls (form f_build_email_data ) y la construcción del correo electrónico.
FORM lanza_envio_email.
* miro si la tabla de emails esta vacia, intento meter el email del user
DESCRIBE TABLE so_email LINES lv_num_emails.
IF lv_num_emails = 0.
SELECT SINGLE adr6~smtp_addr INTO so_email-low
FROM usr21
INNER JOIN adr6
ON usr21~addrnumber = adr6~addrnumber
AND usr21~persnumber = adr6~persnumber
WHERE bname = sy-uname.
IF sy-subrc EQ 0.
lv_num_emails = lv_num_emails + 1.
so_email-sign = ‘I’.
so_email-option = ‘EQ’.
APPEND so_email.
ENDIF.
ENDIF.
IF lv_num_emails > 0.
* Construimos el catalogo para poder hacer la excel.
CALL FUNCTION ‘LVC_FIELDCATALOG_MERGE’
EXPORTING
i_structure_name = ‘ZME2L’
CHANGING
ct_fieldcat = gt_fieldcat
EXCEPTIONS
inconsistent_interface = 1
program_error = 2
OTHERS = 3.
PERFORM modify_fieldcat.
* Constuimos el correo desde la tabla interna.
PERFORM send_email.
ENDIF.
ENDFORM.
*&———————————————————————*
*& Form SEND_EMAIL
*&———————————————————————*
* text
*———————————————————————-*
* –> p1 text
* <– p2 text
*———————————————————————-*
FORM send_email .
DATA:
lt_binary_content TYPE solix_tab,
lv_size TYPE so_obj_len,
r_mail TYPE ace_generic_range_t,
st_mail TYPE ace_generic_range,
lv_count TYPE char2,
lv_var TYPE char8.
FIELD-SYMBOLS: <fs_mail> TYPE any.
REFRESH: lt_binary_content.
CLEAR: st_mail, lv_count, lv_var.
* Construye el objeto binario de la excel a partir de la tabla interna
PERFORM f_build_email_data CHANGING lt_binary_content
lv_size.
DATA: v_rundate LIKE sy-datum,
v_runtime LIKE sy-uzeit,
timestamp(20),
lcl_send_request TYPE REF TO cl_bcs,
lcl_document TYPE REF TO cl_document_bcs,
lv_subject TYPE so_obj_des,
lt_main_text TYPE soli_tab,
lv_text TYPE soli,
lv_filename TYPE sood-objdes,
lv_mailto TYPE adr6-smtp_addr,
lcl_recipient TYPE REF TO cl_cam_address_bcs,
lv_sent_to_all TYPE os_boolean.
*–Run Date and Run Time
v_rundate = sy-datum.
v_runtime = sy-uzeit.
* CONCATENATE v_rundate v_runtime INTO timestamp.
WRITE sy-datum TO timestamp MM/DD/YYYY.
TRY.
* ——– create persistent send request ————————
lcl_send_request = cl_bcs=>create_persistent( ).
* ——– create and set document with attachment —————
* ASUNTO CORREO
CONCATENATE ‘Informe de pedidos’ ‘ Fecha:’ timestamp
sy-cprog sy-sysid INTO lv_subject
SEPARATED BY space.
* Texto de correo (cuerpo del mensaje)
CONCATENATE ‘En el Excel anexo se detallan los pedidos pendientes’
‘en el sistema.’ INTO lv_text SEPARATED BY space.
APPEND lv_text TO lt_main_text.
APPEND text-001 TO lt_main_text.
APPEND text-003 TO lt_main_text.
lcl_document = cl_document_bcs=>create_document(
i_type = ‘RAW’
i_text = lt_main_text
i_subject = lv_subject ). “#EC NOTEXT
* Añadimos la excel al mensaje, poniendo nombre al fichero
CLEAR: lv_subject.
CONCATENATE ‘Pedidos’_’ v_rundate
v_runtime ‘_’ sy-sysid INTO lv_filename.
CALL METHOD lcl_document->add_attachment
EXPORTING
i_attachment_type = ‘xls’
i_attachment_subject = lv_filename
i_attachment_size = lv_size “im_size
i_att_content_hex = lt_binary_content. “im_tab ).
* add document object to send request
lcl_send_request->set_document( lcl_document ).
* ——— add recipient (e-mail address) ———————–
* create recipient object
* Añadimos los destinatarios al correo
LOOP AT so_email.
lv_mailto = so_email-low. “ls_recipient-low.
lcl_recipient = cl_cam_address_bcs=>create_internet_address( lv_mailto ).
* add recipient object to send request
lcl_send_request->add_recipient( lcl_recipient ).
* CLEAR: ls_recipient.
ENDLOOP.
* Send now
lcl_send_request->set_send_immediately( ‘ ‘ ).
* Outbox
lcl_send_request->send_request->set_link_to_outbox( ‘X’ ).
* ———- send document —————————————
lv_sent_to_all = lcl_send_request->send( i_with_error_screen = ‘X’ ).
COMMIT WORK.
IF lv_sent_to_all IS INITIAL.
MESSAGE i500(sbcoms) WITH lv_mailto.
ELSE.
MESSAGE s022(so).
ENDIF.
* ———— exception handling ———————————-
* replace this rudimentary exception handling with your own one !!!
* CATCH cx_bcs INTO lcl_bcs_exception.
* MESSAGE i865(so) WITH lcl_bcs_exception->error_type.
ENDTRY.
ENDFORM.
FORM f_build_email_data CHANGING p_lt_binary_content
TYPE STANDARD TABLE
p_size TYPE so_obj_len.
DATA: e_xstring TYPE xstring.
DATA: mt_fcat TYPE lvc_t_fcat,
ms_fcat TYPE lvc_s_fcat,
st_fieldcat TYPE slis_fieldcat_alv.
DATA: mt_data TYPE REF TO data.
DATA: m_flavour TYPE string.
DATA: m_version TYPE string.
DATA: mo_result_data TYPE REF TO cl_salv_ex_result_data_table.
DATA: mo_columns TYPE REF TO cl_salv_columns_table.
DATA: mo_aggreg TYPE REF TO cl_salv_aggregations.
DATA: mo_salv_table TYPE REF TO cl_salv_table.
DATA: m_file_type TYPE salv_bs_constant.
DATA: out_length TYPE i.
FIELD-SYMBOLS <tab> TYPE ANY TABLE.
CLEAR: e_xstring, ms_fcat, st_fieldcat, m_flavour, m_version,
mo_result_data, mo_columns, mo_aggreg, mo_salv_table,
m_file_type, out_length, mt_data.
* REFRESH: it_fieldcat[].
*-It_final here is the final itab same parameter you pass in
* your alv grid
GET REFERENCE OF gt_eban INTO mt_data.
*-Move your field catalog to mt_fcat make sure to populate
*-ms_fcat-seltext, because it can be that in your field cat the headings
*-are in seltext_l or seltext_m or seltext_s
LOOP AT gt_fieldcat INTO ms_fcat. “st_fieldcat.
* MOVE-CORRESPONDING st_fieldcat TO ms_fcat.
* MOVE: st_fieldcat-seltext_l TO ms_fcat-seltext.
APPEND ms_fcat TO mt_fcat.
CLEAR: ms_fcat, st_fieldcat.
ENDLOOP.
IF cl_salv_bs_a_xml_base=>get_version( ) EQ if_salv_bs_xml=>version_25 OR
cl_salv_bs_a_xml_base=>get_version( ) EQ if_salv_bs_xml=>version_26.
mo_result_data = cl_salv_ex_util=>factory_result_data_table(
r_data = mt_data
t_fieldcatalog = mt_fcat
).
CASE cl_salv_bs_a_xml_base=>get_version( ).
WHEN if_salv_bs_xml=>version_25.
m_version = if_salv_bs_xml=>version_25.
WHEN if_salv_bs_xml=>version_26.
m_version = if_salv_bs_xml=>version_26.
ENDCASE.
m_file_type = if_salv_bs_xml=>c_type_xlsx.
m_flavour = if_salv_bs_c_tt=>c_tt_xml_flavour_export.
“transformation of data to excel
CALL METHOD cl_salv_bs_tt_util=>if_salv_bs_tt_util~transform
EXPORTING
xml_type = m_file_type
xml_version = m_version
r_result_data = mo_result_data
xml_flavour = m_flavour
gui_type = if_salv_bs_xml=>c_gui_type_gui
IMPORTING
xml = e_xstring.
ENDIF.
CALL FUNCTION ‘SCMS_XSTRING_TO_BINARY’
EXPORTING
buffer = e_xstring
IMPORTING
output_length = out_length
TABLES
binary_tab = p_lt_binary_content.
MOVE: out_length TO p_size.
ENDFORM. ” F_BUILD_EMAIL_DATA
El resultado el correo enviado podría ser algo parecido a esto, donde podemos personalizar en el código la información del asunto, texto del correo, nombre del fichero anexado, etc.

Con el fichero excel anexado con la información del ALV, todo construido con un desarrollo más o menos sencillo.
Espero que os sea de utilidad.
Bibliografia:
Gracias a Ralph Vincent Ferraren por su aporte en la Wiki del SCN de SAP:
https://wiki.scn.sap.com/wiki/display/ABAP/Send+an+Internal+Table+as+an+excel+attachment+via+email
Hola Roberto,
como siempre un articulo muy interesante y útil.
Gracias por tu trabajo.