본문 바로가기
BAPI · BADI · RFC · Interface

[SAP ABAP] SO_DOCUMENT_SEND_API1 vs SO_NEW_DOCUMENT_SEND_API1 차이 — 발신인 지정·PACKING_LIST 자동 생성 (메일 전송 FM)

by Song.sh 2026. 5. 29.

ABAP 에서 메일을 보낼 때 가장 오래 쓰여온 표준 함수가 SO_DOCUMENT_SEND_API1SO_NEW_DOCUMENT_SEND_API1 입니다. 이름이 비슷해서 "둘 중 뭘 써야 하나" 헷갈리기 쉬운데, 실제로는 역할과 기능이 분명히 다릅니다.

 

결론부터 말하면 SO_NEW_DOCUMENT_SEND_API1 은 내부에서 SO_DOCUMENT_SEND_API1 을 그대로 호출하는 간편 래퍼(wrapper) 입니다. 대신 두 가지를 포기합니다 — (1) 발신인 지정 기능과 (2) PACKING_LIST 세밀 제어. 그 대가로 코드가 짧아지죠.

 

이 글에서는 두 함수의 관계(NEW = 래퍼) → 발신인 지정 차이 → PACKING_LIST 수동 vs 자동 → 전체 시그니처 비교 → 언제 무엇을 쓸지까지 정리합니다. 예시 메일 주소는 가상값(example.com) 으로 표기.

핵심 — NEW 는 OLD 의 간편 래퍼

SO_NEW_DOCUMENT_SEND_API1 의 함수 본문을 열어보면, 결국 마지막에 SO_DOCUMENT_SEND_API1 을 호출합니다. 즉 NEW 는 "PACKING_LIST 를 자동으로 만들어준 뒤 OLD 를 대신 불러주는" 편의 함수입니다.

구분 SO_DOCUMENT_SEND_API1 SO_NEW_DOCUMENT_SEND_API1
관계 실제 전송 로직 (원본) OLD 를 호출하는 간편 래퍼
발신인 지정 가능 (SENDER_ADDRESS) 불가 (항상 로그인 사용자)
PACKING_LIST 직접 작성 (수동) 자동 생성 (DOCUMENT_TYPE 기반)
본문 테이블 CONTENTS_TXT + CONTENTS_BIN OBJECT_CONTENT
코드 길이 길다 (PACKING_LIST 채워야 함) 짧다
적합한 경우 발신인 변경·첨부 세밀 제어 필요 단순 텍스트 메일 빠르게 발송

두 함수 모두 SAPoffice(SO) 패키지의 함수 그룹 SOI1 에 속합니다. 더 새로운 방식인 객체지향 CL_BCS 클래스 기반 송신도 있지만, 이 글은 두 클래식 FM 의 차이에 집중합니다.


차이 1 — 발신인(Sender) 지정 가능 여부

가장 실무적으로 중요한 차이입니다. SO_DOCUMENT_SEND_API1 에는 발신인을 지정하는 IMPORTING 파라미터가 있습니다.

* SO_DOCUMENT_SEND_API1 의 발신인 관련 파라미터
IMPORTING
  VALUE(SENDER_ADDRESS)      LIKE SOEXTRECI1-RECEIVER DEFAULT SY-UNAME
  VALUE(SENDER_ADDRESS_TYPE) LIKE SOEXTRECI1-ADR_TYP  DEFAULT 'B'
EXPORTING
  VALUE(SENDER_ID)           LIKE SOUDK

SENDER_ADDRESS 에 보내는 사람을 직접 넣을 수 있고, SENDER_ADDRESS_TYPE 으로 그 주소가 어떤 형식인지(SAP 사용자 / 외부 이메일 등) 지정합니다. 기본값은 SY-UNAME(현재 로그인 사용자) 와 타입 'B'.

 

반면 SO_NEW_DOCUMENT_SEND_API1 의 시그니처에는 SENDER_ADDRESS 자체가 없습니다. 내부에서 OLD 를 호출할 때 발신인 인자를 넘기지 않기 때문에, 발신인은 항상 메일을 발송하는 현재 사용자(SY-UNAME) 로 고정됩니다.

파라미터 OLD NEW 의미
SENDER_ADDRESS O X 발신인 주소
SENDER_ADDRESS_TYPE O X 발신인 주소 타입
SENDER_ID O X 생성된 발신인 ID 반환

배치 잡이나 시스템 계정으로 메일을 보내되 발신인 표시는 특정 담당자/대표 주소로 보이게 하고 싶다면 반드시 SO_DOCUMENT_SEND_API1 을 써야 합니다.


차이 2 — PACKING_LIST 수동 작성 vs 자동 생성

두 번째 차이는 메일 본문/첨부를 구성하는 PACKING_LIST 의 처리 방식입니다.

SO_DOCUMENT_SEND_API1PACKING_LIST (타입 SOPCKLSTI1) 를 호출자가 직접 채워야 합니다. 본문이 몇 번째 줄부터 시작하는지(body_start), 몇 줄인지(body_num), 문서 타입은 무엇인지(doc_type) 등을 일일이 세팅합니다. 본문 + 첨부파일 여러 개를 정교하게 묶을 수 있는 대신 코드가 길어집니다.

 

SO_NEW_DOCUMENT_SEND_API1 은 이 PACKING_LIST 를 내부에서 자동으로 한 줄 생성합니다. 함수 본문을 보면 이렇게 동작합니다.

* SO_NEW_DOCUMENT_SEND_API1 내부 — PACKING_LIST 자동 생성
DATA pack_wa TYPE sopcklsti1.
DATA packing_list TYPE TABLE OF sopcklsti1.

pack_wa-doc_type   = document_type.            " IMPORTING DOCUMENT_TYPE (DEFAULT 'RAW')
pack_wa-head_start = 1.
pack_wa-head_num   = lines( object_header ).
pack_wa-body_start = 1.
IF contents_hex[] IS NOT INITIAL.
  pack_wa-body_num   = lines( contents_hex ).
  pack_wa-transf_bin = 'X'.
ELSE.
  pack_wa-body_num   = lines( object_content ).
ENDIF.
APPEND pack_wa TO packing_list.

* 그 다음 SO_DOCUMENT_SEND_API1 을 대신 호출
CALL FUNCTION 'SO_DOCUMENT_SEND_API1'
  EXPORTING document_data = document_data
            ...
  TABLES    packing_list  = packing_list
            contents_txt  = object_content
            ...

호출자는 본문을 OBJECT_CONTENT 테이블에 채우고 DOCUMENT_TYPE 만 지정하면, PACKING_LIST 작성은 함수가 알아서 해줍니다. 단순 텍스트/HTML 메일 한 통을 빠르게 보낼 때 훨씬 간편합니다.


차이 3 — 전체 시그니처 비교

ADT 로 확인한 두 함수의 IMPORTING / TABLES 파라미터를 나란히 비교하면 차이가 한눈에 들어옵니다.

구역 SO_DOCUMENT_SEND_API1 SO_NEW_DOCUMENT_SEND_API1
IMPORTING DOCUMENT_DATA · PUT_IN_OUTBOX · SENDER_ADDRESS · SENDER_ADDRESS_TYPE · COMMIT_WORK · IP_ENCRYPT · IP_SIGN · IV_VSI_PROFILE DOCUMENT_DATA · DOCUMENT_TYPE · PUT_IN_OUTBOX · COMMIT_WORK · IP_ENCRYPT · IP_SIGN
EXPORTING SENT_TO_ALL · NEW_OBJECT_ID · SENDER_ID SENT_TO_ALL · NEW_OBJECT_ID
TABLES PACKING_LIST · OBJECT_HEADER · CONTENTS_BIN · CONTENTS_TXT · CONTENTS_HEX · OBJECT_PARA · OBJECT_PARB · RECEIVERS · ET_VSI_ERROR OBJECT_HEADER · OBJECT_CONTENT · CONTENTS_HEX · OBJECT_PARA · OBJECT_PARB · RECEIVERS

핵심만 추리면 — OLD 에만 있는 것: SENDER_ADDRESS · SENDER_ID · PACKING_LIST.

NEW 에만 있는 것: DOCUMENT_TYPE · OBJECT_CONTENT. NEW 의 OBJECT_CONTENT 는 내부에서 OLD 의 CONTENTS_TXT 로 연결됩니다.


언제 무엇을 쓸까

상황 권장 함수
단순 텍스트/HTML 메일 한 통 빠르게 SO_NEW_DOCUMENT_SEND_API1
발신인을 특정 주소로 표시해야 함 SO_DOCUMENT_SEND_API1
본문 + 첨부 여러 개를 정교하게 묶음 SO_DOCUMENT_SEND_API1
신규 개발 — 더 현대적인 방식 원함 CL_BCS 클래스 (별도 주제)

요약하면 간편함이 우선이면 NEW, 발신인·첨부 제어가 필요하면 OLD. 그리고 신규 개발이라면 두 클래식 FM 대신 객체지향 CL_BCS 기반 송신이 SAP 의 권장 방향입니다.


자주 빠뜨리는 함정

COMMIT_WORK 누락 — 메일이 안 나감

두 함수 모두 COMMIT_WORK 기본값이 SPACE. 호출 후 직접 COMMIT WORK 을 하거나 파라미터를 'X' 로 넘기지 않으면 송신 큐에 들어가지 않습니다. 전송 후 SOST 에서 메일이 안 보이면 이걸 먼저 의심.

NEW 로 발신인 바꾸려다 막힘

SO_NEW_DOCUMENT_SEND_API1 에는 발신인 파라미터가 아예 없습니다. 발신인을 바꾸려고 NEW 의 파라미터를 뒤지지 말고, 처음부터 OLD 를 쓰거나 CL_BCSset_sender 를 쓰세요.

DOCUMENT_TYPE 과 본문 형식 불일치

NEW 에서 HTML 메일을 보내려면 DOCUMENT_TYPE = 'HTM' 으로 지정해야 합니다. 기본값 'RAW' 그대로 두고 HTML 태그를 본문에 넣으면 태그가 그대로 텍스트로 보입니다.

제목 길이 제한

DOCUMENT_DATA-OBJ_DESCR(제목) 은 50자(byte) 제한. 더 긴 제목이 필요하면 본문 첫 줄이나 별도 처리로 보완해야 합니다.

수신자 RECEIVERS 의 REC_TYPE

RECEIVERS 테이블의 REC_TYPE 을 외부 이메일은 'U'(인터넷 주소) 로 지정해야 합니다. 비워두면 SAP 내부 사용자로 해석되어 외부 메일이 안 나갑니다.


전체 코드 — 복사용 통합본

두 함수의 호출 방식을 한 프로그램에 담은 예시입니다. 둘 다 SAP 표준 함수이므로 시그니처 그대로 호출하면 됩니다. 발신인 지정이 필요한 경우(OLD) 와 간편 발송(NEW) 두 가지를 나란히 비교.

*&---------------------------------------------------------------------*
*& Report ZRXX_MAIL_SEND_COMPARE (예시)
*&---------------------------------------------------------------------*
*& SO_DOCUMENT_SEND_API1 (발신인 지정) vs SO_NEW_DOCUMENT_SEND_API1 (간편)
*&---------------------------------------------------------------------*
REPORT zrxx_mail_send_compare.

DATA: gs_docdata TYPE sodocchgi1,
      gt_receiver TYPE TABLE OF somlreci1,
      gs_receiver TYPE somlreci1,
      gt_content  TYPE TABLE OF solisti1,
      gs_content  TYPE solisti1.

* 공통 — 제목 + 수신자 + 본문
START-OF-SELECTION.

  gs_docdata-obj_descr = '메일 제목 예시'.          " 50자 제한

  gs_receiver-receiver = 'someone@example.com'.     " 수신자 (가상)
  gs_receiver-rec_type = 'U'.                       " U = 인터넷 이메일
  APPEND gs_receiver TO gt_receiver.

  gs_content-line = '안녕하세요. 메일 본문입니다.'.
  APPEND gs_content TO gt_content.

* ───────────────────────────────────────────────
* 방법 A) SO_NEW_DOCUMENT_SEND_API1 — 간편 (발신인 = 현재 사용자)
* ───────────────────────────────────────────────
  CALL FUNCTION 'SO_NEW_DOCUMENT_SEND_API1'
    EXPORTING
      document_data              = gs_docdata
      document_type              = 'RAW'           " HTML 이면 'HTM'
      commit_work                = 'X'             " ★ 필수
    TABLES
      object_content             = gt_content      " 본문 (PACKING_LIST 자동)
      receivers                  = gt_receiver
    EXCEPTIONS
      too_many_receivers         = 1
      document_not_sent          = 2
      document_type_not_exist    = 3
      operation_no_authorization = 4
      parameter_error            = 5
      x_error                    = 6
      enqueue_error              = 7
      OTHERS                     = 8.

  IF sy-subrc <> 0.
    MESSAGE 'NEW 송신 실패' TYPE 'I'.
  ENDIF.

* ───────────────────────────────────────────────
* 방법 B) SO_DOCUMENT_SEND_API1 — 발신인 지정 + PACKING_LIST 수동
* ───────────────────────────────────────────────
  DATA: gt_packing TYPE TABLE OF sopcklsti1,
        gs_packing TYPE sopcklsti1.

  gs_packing-transf_bin = space.
  gs_packing-head_start = 1.
  gs_packing-head_num   = 0.
  gs_packing-body_start = 1.
  gs_packing-body_num   = lines( gt_content ).
  gs_packing-doc_type   = 'RAW'.
  APPEND gs_packing TO gt_packing.

  CALL FUNCTION 'SO_DOCUMENT_SEND_API1'
    EXPORTING
      document_data              = gs_docdata
      put_in_outbox              = 'X'
      sender_address             = 'noreply@example.com'  " ★ 발신인 지정
      sender_address_type        = 'INT'                  " INT = 인터넷 주소
      commit_work                = 'X'                    " ★ 필수
    TABLES
      packing_list               = gt_packing            " ★ 수동 작성
      contents_txt               = gt_content
      receivers                  = gt_receiver
    EXCEPTIONS
      too_many_receivers         = 1
      document_not_sent          = 2
      document_type_not_exist    = 3
      operation_no_authorization = 4
      parameter_error            = 5
      x_error                    = 6
      enqueue_error              = 7
      OTHERS                     = 8.

  IF sy-subrc <> 0.
    MESSAGE 'OLD 송신 실패' TYPE 'I'.
  ENDIF.

요약

관점 정리
관계 NEW 는 내부에서 OLD 를 호출하는 간편 래퍼
발신인 OLD = SENDER_ADDRESS 지정 가능 · NEW = 현재 사용자 고정
PACKING_LIST OLD = 수동 작성 · NEW = DOCUMENT_TYPE 기반 자동 생성
본문 테이블 OLD = CONTENTS_TXT · NEW = OBJECT_CONTENT
선택 기준 간편 = NEW · 발신인/첨부 제어 = OLD · 신규 개발 = CL_BCS

두 함수의 차이는 결국 "얼마나 세밀하게 제어할 것인가" 한 가지로 수렴합니다. SO_NEW_DOCUMENT_SEND_API1 은 PACKING_LIST 를 자동 생성해 코드를 줄여주는 대신 발신인 지정을 포기했고, SO_DOCUMENT_SEND_API1 은 손이 더 가는 대신 발신인·첨부를 자유롭게 다룹니다. 발신인을 바꿔야 하는 요구가 나오면 NEW 로는 답이 없으니 처음부터 OLD(또는 CL_BCS) 로 설계하는 게 안전합니다.


Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.

SO_DOCUMENT_SEND_API1 · SO_NEW_DOCUMENT_SEND_API1 의 시그니처(파라미터·테이블·예외) 는 NetWeaver 표준 함수 그룹 SOI1 기준(ECC 6.0 / S/4HANA on-premise) 입니다. 적용 환경 버전에 따라 일부 파라미터가 다를 수 있으니 실제 적용 시 SE37 의 함수 정의를 확인하시기 바랍니다. 예시 메일 주소는 모두 가상값입니다.