Postmortem & Fix · 앱린다(RINDA)

영어 메일에 한국어 Footer가 붙던 문제 —
원인 규명부터 수정·머지까지

제보(영어 콜드메일 하단 한국어 발신자/수신거부) → 코드·beta DB 교차 분석 → 근본 원인 → 영어 고정 수정 → alpha·beta 머지 전 과정 기록.

작성: 2026-06-30 · 머지: alpha #9228 / beta #9229 · 변경 파일 1개

03줄 요약

① 제보 = 시퀀스 “테스트 발송(미리보기)” 한정. 영어 본문 콜드메일 하단에 한국어 footer(“발신자: 박준영…”, “수신거부 | 내 데이터 관리”)가 붙었습니다. 실제 바이어 발송이 아니라 마케터 본인이 받아본 테스트 메일이었습니다.
② 근본 원인 = footer 언어를 “마케터 UI 언어”로 정함. 테스트 발송이 footer 언어로 관리자 화면 언어(i18n.language=ko)를 서버에 넘겼고, 서버가 그대로 한국어 footer를 렌더했습니다.
③ 해결 = 발송 경계(서버)에서 영어로 고정. caller가 무슨 값을 보내든 footer는 영어. 코드 1곳 수정으로 우회 불가하게 차단하고 alpha·beta 양쪽 머지 완료.

1제보 — 무슨 화면이었나

aeroway 영업 메일 하단에 영어 본문과 어울리지 않는 한국어 고지가 붙어 “해외 바이어에게 괜찮은가” 검토 요청이 들어왔습니다.

2원인 추적 — 코드 + beta DB 교차

정적 분석만으론 “코드상 영어가 나와야 하는데 한국어”라는 모순이 생겨, beta DB 실데이터로 발송 경로를 특정했습니다.

1
footer 생성기 발견 — email-footer.service.ts:144 buildComplianceFooter. 6개국어 LABELS, 언어는 input.locale로 분기.
2
locale 결정부 — email.service.ts:702 normalizeLocale(data.complianceLocale). 미지정 시 영어(DEFAULT_LANGUAGE="en").
3
실발송 워커는 complianceLocale을 안 넘김 → 코드상 영어가 맞음. 모순 발생.
4
beta DB 조회 — 제보 메일 subject가 [테스트] ActUEarn…, 발신=수신=aeroway@hi.rinda.ai. 실발송이 아니라 테스트 발송으로 확정.
5
테스트 발송 경로만 footer 언어로 UI 언어를 전달 — TestSendDialog.tsx:157 complianceLocale: toSupportedLanguage(i18n.language)sequences.routes.ts:967sequence-preview.service.ts:217buildComplianceFooter(locale:"ko").
핵심: footer는 “수신자가 읽는 법적 고지”인데, 언어 기준이 수신자(본문) 언어가 아니라 발송자(마케터)의 UI 언어로 잘못 잡혀 있었습니다.

3도입 경위 (git blame)

항목커밋(PR)작성자날짜
Compliance footer 자체 도입(다국어 LABELS)69ba8eb43 (#7601)Gyudong Kim2026-05-19
미리보기·테스트 발송에 complianceLocale 배선 + 프론트가 UI 언어 전송 ← 누수 시작점f7c59543b (#7775)lsuminl2026-05-21

4왜 “영어 고정”인가 (2026 레퍼런스 + DB)

법적 기준
수신자 이해 가능 언어
영어권 발송 비중
≈ 89%
콜드 시퀀스 수신거부
이미 영어 고정

미·EU·한·일 어느 법도 footer를 특정 언어로 규정하지 않고 모두 “수신자가 이해 가능한 clear & conspicuous 고지”를 요구합니다. 영어 본문을 받는 수신자에게 가장 이해 가능한 언어는 영어 → 발송자 모국어(한국어) 고정은 법적 실익 0, 리스크만 증가. 실데이터상 콜드 아웃리치 본문 수신거부 블록은 이미 영어 고정이라, 컴플라이언스 footer도 영어로 맞추는 것이 일관됩니다. (정책 선택: “영어 완전 고정”)

5수정 내용 — email.service.ts 1곳

발송 경계(서버)에서 영어로 강제 → 어떤 caller(테스트 발송/미래 경로)도 우회 불가한 단일 기준(SSOT).

// elysia-server/src/services/email.service.ts (buildComplianceFooter 호출)
  pendingComplianceFooter = buildComplianceFooter({
    workspace: workspaceCtx,
    unsubscribeUrl,
    dsarUrl,
-   locale: normalizeLocale(data.complianceLocale),
+   // 컴플라이언스 풋터는 영어로 고정. 본문(영어)↔풋터 언어 일치로
+   // CAN-SPAM "clear & conspicuous" 충족. caller 의 complianceLocale
+   // (테스트 발송의 UI 언어 등)은 의도적으로 무시.
+   locale: "en",
    recipient: { outreachSourceLabel },
  })

6검증 & 머지

검증결과
type-check (tsgo)PASS (0)
번들 빌드PASS
email-footer 단위 테스트18 pass / 0 fail
lint (email.service.ts)clean
브랜치PR커밋
alpha#92284523aed2d
beta (alpha 체리픽, drift 없음)#9229b70e20875

부수 처리: CI의 biome auto-fix가 무관 파일(auto-add-buyer…)의 s!s?를 바꿔 타입에러를 유발 → 그 파일은 원복하여 email.service.ts 단일 변경으로 깨끗하게 머지.

7이번 범위 밖 — 남은 과제

① CAN-SPAM 물리주소 누락 (별도 P0) 실발송 98.7%를 담당하는 본문 unsubscribe 블록(getSimpleUnsubscribeFooter, 영어·주소 없음)은 그대로이고, 발신자 주소를 담은 buildComplianceFooter는 실발송에 0.17%만 붙습니다. 언어가 아니라 footer 통합·주소 주입 문제 — 근본 원인 규명 후 별도 PR 권장.
② 한국어 캠페인(10.8%)도 이제 영어 footer “영어 완전 고정” 정책 선택의 결과. 향후 “발송 언어 종속”으로 바꾸면 한국어 캠페인엔 한국어 footer가 붙도록 전환 가능(필드·LABELS 유지해 둠).