← All posts

Sending Files from AL11 to an SFTP Server with SAP Cloud Integration

A complete walkthrough — testing the SSH connection, adding the partner's host key to known_hosts, building the iFlow and posting files from AL11 with a small ABAP report.

Cloud IntegrationSFTPSSHAL11ABAP

A very common requirement: S/4HANA writes a file to the application server (AL11) — invoices, payments, stock lists — and a partner wants it on their SFTP server. In this post we build that flow with SAP Cloud Integration (part of Integration Suite), from the first connectivity test to the file arriving on the other side.

The complete flow: AL11 → ABAP report → iFlow → partner SFTP
The complete flow: AL11 → ABAP report → iFlow → partner SFTP

The idea

Cloud Integration runs in the cloud and cannot see the file system of your on-premise application server. So we turn the direction around:

  1. A small ABAP report reads the file from AL11 and posts it to an HTTPS endpoint of an iFlow.
  2. The iFlow writes it to the partner's server with the SFTP receiver adapter.
  3. The report moves the original file to an archive folder.

An alternative is an SFTP sender adapter that polls an SFTP server inside your network through the Cloud Connector. That needs an SFTP server on your side; the push approach above does not need anything extra.

What you need from the partner

Information Example
Host and port sftp.partner-example.com:22
User s4_upload
Authentication Password or public key
Target directory /inbound/
IP allow-list? If yes, send them the outbound IP addresses of your Cloud Integration region

1. Test the connection and get the host key

Open Monitor → Integrations and APIs → Manage Security → Connectivity Tests and switch to the SSH tab.

  • Host / Port: the partner's server
  • Proxy Type: Internet
  • Authentication: None for the first try
  • Leave Check Host Key unchecked — we don't know the key yet

Click Send. If the server is reachable, the response shows its host key. Click Copy Host Key.

SSH connectivity test: the server answers with its host key
SSH connectivity test: the server answers with its host key

If the test ends with a timeout, it is almost always a firewall: the partner has not allowed your Cloud Integration IP addresses yet.

2. Add the host key to known_hosts

The SFTP adapter only talks to servers it knows. The list of known servers is a security material named known_hosts. This check is what protects you from someone pretending to be the partner's server.

Go to Manage Security → Security Material:

  • If known_hosts already exists, download it first and add the new line at the end. Never upload a file that contains only the new key — the hosts of all other integrations would be lost.
  • Then choose Upload → Known Hosts (SSH), keep the name known_hosts and deploy.
known_hosts.txt
# one line per host:  <host> <key type> <base64 public key>
sftp.old-partner.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7v...
sftp.partner-example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM8wq2xYkRb4Tq3Vn0e7HhGfPz1cL5uXo9Ks2dWm4AaQe
Uploading the extended known_hosts file
Uploading the extended known_hosts file

3. Store the credentials

  • Password: Security Material → Create → User Credentials, e.g. name SFTP_PARTNER_USER.
  • Public key: Keystore → Create → SSH Key. Download the public OpenSSH key and send it to the partner — the private key never leaves the tenant. In the adapter you then refer to it with Private Key Alias.

4. Test again — this time for real

Back in the SSH connectivity test:

  • Authentication: User Credentials with SFTP_PARTNER_USER (or Public Key)
  • Check Host Key: ✓
  • Check Directory Access: ✓ with /inbound/

When this test is green, the Cloud Integration side is ready. Everything that fails from now on is in the iFlow or in ABAP — which makes troubleshooting much easier.

5. Build the iFlow

The iFlow and the SFTP receiver settings
The iFlow and the SFTP receiver settings

HTTPS sender adapter

  • Address: /al11/sftp-out
  • User Role: ESBMessaging.send
  • CSRF Protected: unchecked — our ABAP report doesn't fetch a token

Runtime configuration of the iFlow: put FileName into Allowed Header(s). Otherwise Cloud Integration drops the header and the file name is lost.

Content Modifier — decide the target file name:

content-modifier.txt
Message Header
  Name:        TargetFile
  Source Type: Expression
  Source Value: ${header.FileName}

Optional – add a timestamp to avoid overwriting:
  Source Value: ${date:now:yyyyMMdd_HHmmss}_${header.FileName}

SFTP receiver adapter

Field Value
Address sftp.partner-example.com:22
Proxy Type Internet
Authentication User Name/Password
Credential Name SFTP_PARTNER_USER
Directory /inbound/
File Name ${header.TargetFile}
Handling for Existing Files Fail — safer than overwriting

Deploy the iFlow and copy its endpoint from Monitor → Manage Integration Content.

6. The ABAP side: SM59 and the report

Create an HTTP destination of type G in SM59:

  • Target Host: the runtime host of your tenant (...-rt.cfapps.<region>.hana.ondemand.com)
  • Port: 443, SSL: active
  • Path Prefix: /http/al11/sftp-out
  • Logon: basic authentication with clientid / clientsecret from a service key of the Process Integration Runtime (plan integration-flow), or a client certificate

Import the server certificate chain into STRUST (SSL client identity) so the TLS handshake works.

The files waiting in AL11:

Files waiting in the outbound directory (AL11)
Files waiting in the outbound directory (AL11)

And the report:

zal11_to_cpi_sftp.prog.abap
REPORT zal11_to_cpi_sftp.

" Reads a file from the application server (AL11), posts it to a
" Cloud Integration iFlow and moves it to an archive folder.
" Classic ABAP (on-premise): OPEN DATASET is not available in ABAP Cloud.

PARAMETERS: p_dir  TYPE c LENGTH 200 LOWER CASE DEFAULT '/interface/sftp_out/',
            p_file TYPE c LENGTH 120 LOWER CASE OBLIGATORY,
            p_arch TYPE c LENGTH 200 LOWER CASE DEFAULT '/interface/sftp_out/archive/'.

CONSTANTS c_destination TYPE rfcdest VALUE 'ZCPI_SFTP_OUT'.

START-OF-SELECTION.
  DATA(path)    = |{ p_dir }{ p_file }|.
  DATA(archive) = |{ p_arch }{ p_file }|.
  DATA content TYPE xstring.

  " 1. Read the file from AL11
  TRY.
      OPEN DATASET path FOR INPUT IN BINARY MODE.
      IF sy-subrc <> 0.
        MESSAGE |File { path } cannot be opened| TYPE 'E'.
      ENDIF.
      READ DATASET path INTO content.
      CLOSE DATASET path.
    CATCH cx_sy_file_access_error INTO DATA(file_error).
      MESSAGE file_error->get_text( ) TYPE 'E'.
  ENDTRY.

  " 2. Post it to the iFlow (SM59 destination of type G)
  DATA client TYPE REF TO if_http_client.
  cl_http_client=>create_by_destination(
    EXPORTING  destination = c_destination
    IMPORTING  client      = client
    EXCEPTIONS OTHERS      = 1 ).
  IF sy-subrc <> 0.
    MESSAGE |Destination { c_destination } cannot be used (SM59)| TYPE 'E'.
  ENDIF.

  client->request->set_method( if_http_request=>co_request_method_post ).
  client->request->set_content_type( 'application/octet-stream' ).
  client->request->set_header_field( name = 'FileName' value = CONV #( p_file ) ).
  client->request->set_data( content ).

  client->send( EXCEPTIONS OTHERS = 1 ).
  IF sy-subrc = 0.
    client->receive( EXCEPTIONS OTHERS = 1 ).
  ENDIF.
  IF sy-subrc <> 0.
    DATA error_text TYPE string.
    client->get_last_error( IMPORTING message = error_text ).
    MESSAGE error_text TYPE 'E'.
  ENDIF.

  DATA status TYPE i.
  DATA reason TYPE string.
  client->response->get_status( IMPORTING code = status reason = reason ).
  client->close( ).
  IF status <> 200.
    MESSAGE |Cloud Integration answered { status } { reason }| TYPE 'E'.
  ENDIF.

  " 3. Archive: write a copy, then delete the original
  OPEN DATASET archive FOR OUTPUT IN BINARY MODE.
  TRANSFER content TO archive.
  CLOSE DATASET archive.
  DELETE DATASET path.

  MESSAGE |{ p_file } sent to the SFTP server and archived| TYPE 'S'.

For production use, consider:

  • Logical file names (transaction FILE) instead of free paths, plus an authorization check on S_DATASET.
  • A background job (SM36) that loops over the directory instead of one file per run.

7. Test end to end

  1. Run the report with a file name from AL11.
  2. In Monitor → Message Processing the message should be Completed.
  3. The file is in the partner's /inbound/ folder, and in AL11 it moved to archive/.

Troubleshooting

Symptom Likely cause Fix
Auth fail / host key rejected Host key missing or changed Step 2 — update known_hosts
Connection timed out Firewall / allow-list Partner allows your CPI IP addresses
No such file / permission denied Wrong directory or rights Connectivity test with Check Directory Access
HTTP 401 / 403 in ABAP Wrong client ID/secret or role Check the service key and ESBMessaging.send
HTTP 403 with CSRF message CSRF protection is on Uncheck CSRF Protected
File has the wrong name FileName header dropped Add it to Allowed Header(s)
"File already exists" Handling for Existing Files = Fail Add a timestamp to the file name

The nice thing about this setup: every part can be tested on its own — the SSH connection, the iFlow and the ABAP report. When something breaks, you know exactly where to look.

Comments

Leave a comment