파일·리소스 처리 · Operations

개별 파일은 작아도 메일은 실패한다: 총 첨부 용량을 사전에 검증하는 방법

파일별 크기는 제한 안에 있지만 한 번에 보내는 첨부 합계가 업무 메일의 허용 범위를 넘는 조건을 분석하고, 여러 화면에서 총량을 일관되게 검증한 과정을 정리합니다.

JavaJavaScriptJSPEmailFile ValidationGoogle Workspace

문제의 출발점

첨부파일 검증을 파일 하나씩만 수행하면 모든 파일이 개별 제한을 통과하면서도 메일 전체는 발송할 수 없는 상태가 생긴다.

이번 업무 환경에서는 한 번에 보내는 첨부 용량이 24MB 이상이면 Google Drive 전환 조건과 기존 메일 발송 흐름이 맞지 않아 정상 발송되지 않았다. 여러 메일 화면에서 개별 파일이 아니라 전체 첨부파일의 합계를 계산해, 사용자가 발송을 시도하기 전에 안내하고 차단하도록 개선했다.

여기서 24MB는 해당 시스템에서 확인한 업무 기준이다. Google Workspace나 모든 이메일 서비스에 보편적으로 적용되는 공식 최대 용량을 뜻하지 않는다.

개별 제한과 누적 제한은 다른 규칙이다

예를 들어 개별 파일 제한이 24MB라고 가정하고 다음 세 파일을 첨부했다고 생각해 보자.

개별 제한과 누적 제한은 다른 규칙이다 데이터 표
파일크기개별 검사
A10MB통과
B8MB통과
C7MB통과
합계25MB발송 조건 초과

각 파일은 모두 제한보다 작지만 합계는 24MB 이상이다. 검사식을 파일 반복문 안에만 두고 현재 파일 크기만 비교하면 이 요청은 통과한다.

따라서 다음 두 질문을 별도로 답해야 한다.

  • 이 파일 하나를 받을 수 있는가
  • 지금 선택된 모든 파일을 한 번의 메일로 보낼 수 있는가

첫 번째는 항목 제약이고 두 번째는 요청 전체의 집계 제약이다.

외부 플랫폼의 전환 동작이 기존 흐름과 충돌했다

문제의 원인은 메일 플랫폼이 큰 첨부를 다루는 방식과 기존 업무 시스템의 기대가 달랐다는 데 있었다.

해당 환경에서 24MB 이상 첨부는 Google Drive 전환 조건에 들어갔고, 기존 시스템의 메일 생성·발송 흐름은 그 전환을 정상적으로 처리하지 못했다. 메일 플랫폼 자체를 수정하거나 Drive 전환 기능을 새로 개발한 것은 아니다.

대신 업무 시스템이 지원할 수 있는 범위를 명시하고, 그 범위를 넘는 요청을 발송 전에 차단했다. 외부 서비스의 기능을 모두 수용하기보다 현재 연계 계약이 보장하는 경계를 사용자에게 먼저 알려 주는 방식이었다.

합계는 첨부 목록이 바뀔 때마다 다시 계산해야 한다

총량 검증은 발송 버튼을 누르는 순간 한 번만 실행하는 것보다, 첨부 상태가 바뀔 때마다 현재 합계를 갱신하는 편이 사용자 경험에 유리하다.

첨부 추가:
    현재 첨부 목록에 파일 반영
    전체 용량 다시 계산
    제한 이상이면 안내하고 발송 비활성화

첨부 삭제:
    현재 첨부 목록에서 파일 제거
    전체 용량 다시 계산
    제한 안이면 발송 가능 상태 복구

기존 합계에 새 파일 크기만 계속 더하면 삭제·재선택·중복 선택 과정에서 화면 상태와 실제 첨부 목록이 달라질 수 있다. 현재 목록을 기준으로 재계산하면 상태 전이를 단순하게 유지할 수 있다.

위 구조는 재사용 가능한 설명이며, 내부 JavaScript 함수명이나 화면 구현을 복원한 코드는 아니다.

화면 안내와 서버의 최종 검증을 나눴다

화면에서는 사용자가 첨부를 선택한 직후 합계를 알려 줄 수 있다. 그러나 브라우저 상태만으로 최종 발송을 허용하면 직접 구성된 요청이나 오래 열린 화면을 통제할 수 없다.

개념적인 책임 분리는 다음과 같다.

브라우저:
    선택된 파일의 합계를 빠르게 계산
    업무 기준 이상이면 즉시 안내

서버:
    실제 요청으로 들어온 첨부의 합계를 다시 계산
    업무 기준 이상이면 메일 생성·발송 전에 중단

아래는 실제 상수와 환산식을 포함하지 않은 pseudocode다.

totalSize = sum(request.attachments.size)

if totalSize >= businessLimit:
    return attachmentLimitError

sendMail(request)

24MB를 몇 바이트로 환산했는지는 공개 근거에서 확인하지 않았기 때문에 MB와 MiB를 임의로 동일시하거나 실제 상수 값을 만들지 않는다. 클라이언트와 서버가 같은 업무 기준과 비교 연산을 사용해야 한다는 원칙만 남긴다.

여러 화면에 같은 정책을 적용했다

메일 발송 화면이 여러 업무에 흩어져 있으면 한 화면만 고쳐서는 같은 문제가 다른 경로에서 반복된다.

이번 개선에서는 여러 주문·분석 업무의 메일 화면에 동일한 총 첨부 용량 제한을 적용하고, 화면별 안내 메시지와 발송 차단 조건을 구현했다. 본사와 해외 업무 시스템의 관련 경로도 함께 반영했다.

공통 규칙은 “한 번의 발송에 포함되는 전체 첨부 합계”였다. 화면마다 첨부 UI와 기존 로직은 달라도 최종 판단 기준이 달라지지 않도록 맞춘 것이 중요했다.

경계값 테스트와 확인된 검증 범위를 구분했다

누적 제한을 테스트할 때 일반적으로 필요한 조건은 다음과 같다.

  • 파일 하나가 제한보다 작은 경우
  • 여러 파일의 합계가 제한 바로 아래인 경우
  • 합계가 제한에 도달하거나 넘어가는 경우
  • 첨부 삭제 후 합계가 다시 제한 안으로 들어오는 경우

이는 같은 유형의 시스템에 적용할 수 있는 권장 테스트 관점이다. 실제 검증 기록의 세부 시나리오 이름을 공개 정보 없이 임의로 이 네 항목과 일치시켜 만들지는 않는다.

확인된 사실은 4개의 고유 시나리오를 내부와 사용자 단계에서 반복했고, 총 8행이 모두 Y였다는 것이다.

경계값 테스트와 확인된 검증 범위를 구분했다 데이터 표
고유 시나리오검증 단계총 기록
4개내부·사용자 반복8행 Y

따라서 “8개의 서로 다른 테스트 시나리오”로 집계하지 않는다. 최종 완료 상태와 관련 화면의 적용 범위가 확인된 수준으로 표현한다.

사용자가 보내고 나서 실패하게 두지 않은 이유

메일 발송은 사용자의 업무 흐름에서 비교적 마지막 단계다. 수신자와 제목, 본문, 첨부를 모두 준비한 뒤 실패하면 다시 파일을 줄이거나 나눠 보내야 한다.

서버 예외만 반환하는 방식보다 첨부 선택 단계에서 현재 합계와 제한을 알려 주면 다음 이점이 있다.

  • 실패 원인을 발송 전에 이해할 수 있다.
  • 어떤 첨부를 줄이거나 나눌지 사용자가 선택할 수 있다.
  • 외부 메일 플랫폼의 전환 동작에 진입하기 전에 통제할 수 있다.
  • 여러 화면이 같은 기준으로 동작한다.

다만 빠른 화면 안내가 서버 검증을 대신하지는 않는다.

남는 한계

24MB는 이번 업무 시스템과 당시 외부 플랫폼 연계에서 확인한 기준이다. 다른 메일 서버, 인코딩 방식, 본문 구성과 중계 경로에서는 적절한 값이 달라질 수 있다.

첨부 원본 크기의 합계와 실제 메일 전송 크기도 항상 같지는 않다. 인코딩과 메시지 구성에 따른 오버헤드를 엄밀히 통제해야 하는 시스템이라면 전송 단계의 크기 계산 기준을 별도로 확인해야 한다. 이번 작업이 모든 이메일 시스템의 용량 문제를 해결했다는 뜻은 아니다.

정리

개별 항목이 모두 유효하다고 요청 전체가 유효한 것은 아니다. 파일 업로드, 장바구니, 배치 건수처럼 여러 항목이 하나의 요청으로 묶일 때는 합계·개수·시간 같은 집계 제약이 별도로 필요하다.

이번 개선의 핵심은 24MB라는 숫자 자체가 아니다. 개별 파일 검사와 한 번의 발송 전체에 대한 검사를 구분하고, 사용자가 긴 입력을 마친 뒤 실패하기 전에 현재 시스템이 지원하는 경계를 알려 준 것이었다.