Technical Articles
Send password protected ZIP file (PDF file inside ZIP folder) from SAP via email
This blog describes the procedure to email a ZIP file (PDF file inside ZIP folder) with password protection, as an attachment. Normally, we have a scenario where we convert the OTF output of a Smartform, or a spool request to PDF.
Without using any third-party tool, we can password protect the ZIP file (pdf file inside the ZIP folder) and send it via email using SAP.
Business Scenario:
Generate a payslip using smartform, encrypt it with a password and send it to the employee via email.
Prerequisites
- You are able to generate a smartform with OTF data
STEP 1
Convert OTF of a smartform to PDF file
DATA: i_otf TYPE itcoo OCCURS 0 WITH HEADER LINE,
i_tline TYPE TABLE OF tline WITH HEADER LINE,
v_len_in LIKE sood-objlen.
CALL FUNCTION 'CONVERT_OTF'
EXPORTING
format = 'PDF'
max_linewidth = 132
IMPORTING
bin_filesize = v_len_in
TABLES
otf = i_otf
lines = i_tline
EXCEPTIONS
err_max_linewidth = 1
err_format = 2
err_conv_not_possible = 3
OTHERS = 4.
STEP 2
Move the PDF file to the Application server. In the below scenario we are moving the file to /tmp/ directory in AL11 Transaction, One in .PDF format and the other in .ZIP format.
DATA: l_file TYPE string,
l_file_zip TYPE string,
itab_attach TYPE xstring,
t_attachment TYPE solix_tab.
CLEAR:l_file,l_file_zip,itab_attach.
REFRESH:t_attachment[].
CONCATENATE '/tmp/' wa_final-pernr '''.PDF' INTO l_file.
CONCATENATE '/tmp/' wa_final-pernr '''.zip' INTO l_file_zip.
REPLACE ALL OCCURRENCES OF '''' IN l_file WITH space.
REPLACE ALL OCCURRENCES OF '''' IN l_file_zip WITH space.
****code move PDF to server location***
OPEN DATASET l_file FOR OUTPUT IN BINARY MODE .
IF sy-subrc = 0 .
LOOP AT i_tline.
TRANSFER i_tline TO l_file .
ENDLOOP.
CLOSE DATASET l_file .
ELSE.
WRITE : / 'operating system could not open file' .
ENDIF.
***end server code***
STEP 3
Configure the external command using the transaction SM69. Refer to the below screenshot for information to be maintained as part of the configuration.
SM69-External Command
STEP 4
Use the below source code and get external commands from Transaction SM69, and encrypt the file with a password using SXPG_COMMAND_EXECUTE Function module.
DATA: BEGIN OF command_list OCCURS 0.
INCLUDE STRUCTURE sxpgcolist.
DATA: END OF command_list .
DATA: BEGIN OF exec_protocol OCCURS 0.
INCLUDE STRUCTURE btcxpm.
DATA: END OF exec_protocol.
DATA: status LIKE btcxp3-exitstat,
commandname LIKE sxpgcolist-name VALUE 'ZDJ_ENCRYPTPDF',
sel_no LIKE sy-tabix.
* GET LIST OF EXTERNAL COMMANDS
CALL FUNCTION 'SXPG_COMMAND_LIST_GET'
EXPORTING
commandname = commandname
operatingsystem = sy-opsys
TABLES
command_list = command_list
EXCEPTIONS
OTHERS = 1.
CALL FUNCTION 'SXPG_COMMAND_CHECK'
EXPORTING
commandname = command_list-name
operatingsystem = sy-opsys
EXCEPTIONS
no_permission = 1
command_not_found = 2
parameters_too_long = 3
security_risk = 4
wrong_check_call_interface = 5
x_error = 6
too_many_parameters = 7
parameter_expected = 8
illegal_command = 9
communication_failure = 10
system_failure = 11
OTHERS = 12.
CLEAR command_list.
REFRESH command_list.
DATA: v_dir_input TYPE sxpgcolist-parameters.
DATA:l_orln LIKE drao-orln,
l_data_tab LIKE rcgrepfile OCCURS 10 WITH HEADER LINE,
l_lines TYPE i.
CLEAR: v_dir_input,l_orln,l_lines.
REFRESH:l_data_tab[].
command_list-name = 'ZDJ_ENCRYPTPDF'. " External command u have created
command_list-opsystem = 'Linux'.
CONSTANTS: c_extcom TYPE sxpgcolist-name VALUE 'ZDJ_ENCRYPTPDF',
c_oper TYPE syopsys VALUE 'Linux'.
*encrypting the file using some number- Civil ID here is social security ID, AAdhar ID country specific
IF wa_final-civil_id IS NOT INITIAL.
CONCATENATE '-P' wa_final-civil_id l_file_zip l_file INTO v_dir_input SEPARATED BY space.
ENDIF.
*encrypting the file using passport number if no ID available
IF wa_final-civil_id IS INITIAL.
CONCATENATE '-P' wa_final-passport_no l_file_zip l_file INTO v_dir_input SEPARATED BY space.
ENDIF.
DATA: t_result TYPE STANDARD TABLE OF btcxpm.
REFRESH:t_result[].
CALL FUNCTION 'SXPG_COMMAND_EXECUTE'
EXPORTING
commandname = c_extcom
additional_parameters = v_dir_input
operatingsystem = c_oper
TABLES
exec_protocol = t_result
EXCEPTIONS
no_permission = 1
command_not_found = 2
parameters_too_long = 3
security_risk = 4
wrong_check_call_interface = 5
program_start_error = 6
program_termination_error = 7
x_error = 8
parameter_expected = 9
too_many_parameters = 10
illegal_command = 11
wrong_asynchronous_parameters = 12
cant_enq_tbtco_entry = 13
jobcount_generation_error = 14
OTHERS = 15.
STEP 5
Now we need to send the above-encrypted PDF file to an email ID
Convert the file to BINARY data using the below function module:
sy-cprog = 'RC1TCG3Y'.
CALL FUNCTION 'C13Z_RAWDATA_READ'
EXPORTING
i_file = i_file_appl
IMPORTING
e_file_size = l_orln
e_lines = l_lines
TABLES
e_rcgrepfile_tab = l_data_tab
EXCEPTIONS
no_permission = 1
open_failed = 2
read_error = 3
* Begin Correction 24.09.2010 1505368 ********************
path_error = 4
OTHERS = 5.
sy-cprog = sy-repid.
STEP 6
Convert the above BINARY data to XSTRING using the below function module:
DATA:
ld_buffer TYPE xstring,
lv_orln TYPE i.
CLEAR:ld_buffer,lv_orln.
lv_orln = l_orln.
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
EXPORTING
input_length = lv_orln
* first_line = ld_first_line
* last_line = ld_last_line
IMPORTING
buffer = ld_buffer
TABLES
binary_tab = l_data_tab
EXCEPTIONS
failed = 1
. " SCMS_BINARY_TO_XSTRING
STEP 7
Now to attach the PDF file in an email when sending we need to convert the above LD_BUFFER data to HEX format using the below Call method XSTRING_TO_SOLIX:
DATA content_hex TYPE solix_tab.
REFRESH:content_hex[].
CALL METHOD cl_bcs_convert=>xstring_to_solix
EXPORTING
iv_xstring = ld_buffer
RECEIVING
et_solix = content_hex.
STEP 8
Below Logic is for Email to be sent with a PDF attachment from SAP to an employee
DATA: lo_send_request TYPE REF TO cl_bcs
,lo_document TYPE REF TO cl_document_bcs
,lo_sender TYPE REF TO if_sender_bcs
,lo_recipient TYPE REF TO if_recipient_bcs ,
lt_message_body TYPE bcsy_text
,lx_document_bcs TYPE REF TO cx_document_bcs
,lv_send TYPE ad_smtpadr VALUE 'xyz@gmail.com'
,lv_sent_to_all TYPE os_boolean .
DATA recipient TYPE REF TO if_recipient_bcs.
"create send request
lo_send_request = cl_bcs=>create_persistent( ).
DATA gv_message TYPE string.
DATA gv_subject TYPE so_obj_des.
DATA gv_subject1 TYPE so_obj_des.
CLEAR:gv_message,gv_subject,gv_subject1.
"create message body and subject
CONCATENATE 'Dear' wa_final-ename INTO gv_message SEPARATED BY space.
CONCATENATE gv_message ',' INTO gv_message..
APPEND gv_message TO lt_message_body.
CLEAR:gv_message.
APPEND INITIAL LINE TO lt_message_body.
CONCATENATE 'Please find your payslip for the month of' gv_month gv_year 'attached with the mail.' INTO gv_message SEPARATED BY space.
APPEND gv_message TO lt_message_body.
CLEAR:gv_message.
APPEND INITIAL LINE TO lt_message_body.
IF wa_final-civil_id IS NOT INITIAL.
APPEND 'For added security concerns, your payslip is protected by a unique password, which is your Civil ID number.' TO lt_message_body.
ENDIF.
IF wa_final-civil_id IS INITIAL.
APPEND 'For added security concerns, your payslip is protected by a unique password, which is your Passport number.' TO lt_message_body.
ENDIF.
APPEND INITIAL LINE TO lt_message_body.
APPEND 'Regards,' TO lt_message_body.
APPEND 'HR Department' TO lt_message_body.
CONCATENATE 'Your Payslip for' gv_month gv_year INTO gv_subject SEPARATED BY space.
"put your text into the document
lo_document = cl_document_bcs=>create_document(
i_type = 'RAW'
i_text = lt_message_body
i_subject = gv_subject ).
CONCATENATE 'YourPayslip_' gv_month gv_year INTO gv_subject1.
CONDENSE gv_subject1.
TRY.
lo_document->add_attachment(
EXPORTING
i_attachment_type = 'ZIP'
i_attachment_subject = gv_subject
i_att_content_hex = content_hex ).
CATCH cx_document_bcs INTO lx_document_bcs.
ENDTRY.
* Add attachment
* Pass the document to send request
lo_send_request->set_document( lo_document ).
lo_sender = cl_cam_address_bcs=>create_internet_address( 'sap.support@domain.com' ).
lo_send_request->set_sender( lo_sender ).
*--------- add recipient (e-mail address) -----------------------
* create recipient object
DATA:lv_email TYPE pa0105-usrid_long.
CLEAR:lv_email.
SELECT SINGLE usrid_long FROM pa0105 INTO lv_email WHERE pernr = wa_final-pernr AND subty ='0010' AND endda = '99991231'.
IF lv_email IS NOT INITIAL.
recipient = cl_cam_address_bcs=>create_internet_address( lv_email ).
lo_send_request->add_recipient( recipient ).
DATA sent_to_all TYPE os_boolean.
sent_to_all = lo_send_request->send( i_with_error_screen = 'X' ).
COMMIT WORK.
ENDIF.
DELETE DATASET l_file.
DELETE DATASET l_file_zip.
CONCLUSION
Now you can generate a ZIP FILE (PDF file inside the ZIP folder) of a smartform, encrypt the file with a password of your choice using external commands, and can send it as an attachment to an employee via email.
Thanks for reading this blog post.
Please correct me if mistaken at some point, also suggest improvement points.
I hope this blog post will be helpful. If you have questions/suggestions/issues about this, please feel free to leave them in the comments section.
I would like to see your comments and would like to answer questions which you can post at Q&A tag area: https://answers.sap.com/tags/66233466-fcd6-45d2-a9ae-2cba38c72e19
Thanks for sharing.
Just a small semantic correction: You are basically creating a password-protected ZIP file and not a password-protected PDF.
Thank you for your comment, I have updated the blog post accordingly
There is an old blog post on the same subject: https://blogs.sap.com/2012/07/06/email-pdf-attachment-with-password-protection/
But, in general, approach is the same: using external command. It's probably worth mentioning that it requires additional software (i.e. a program that will be executed by the external command) and comes with some security risks.
Not to throw shade on this post but I'm wondering if such requirements even make sense to pursue using ABAP these days. There are better and more secure alternatives to emailing password-protected files, when it comes to secure data exchange. Just a thought.
Hi Vipin,
Thank you for the post. If I need to send a txt file inside the zip and do the same. I have created the external command in SM69 but somehow it is not working. Not sure if I am missing anything. and also not clear about the FM C13Z_RAWDATA_READ. Do I need to add any external command or anything addition to SM69 configuration ? And also what are you sending in i_file_appl ?
Hi Raka,
I´m facing the same problem as you. I do not know what Vipin sent to i_file_appl.
Did you manage to solve this problem?
Best regards.
I had to go in depth in your ABAP code to understand the approach you have used. So, if anyone wonders, the approach was: