2P by GN⁺ 2일전 | ★ favorite | 댓글 1개
  • 최근 트위터에 옛 이메일 인용문이 퍼지며, 문장 끝의 등호(=) 가 왜 생기는지에 대한 의문이 제기됨
  • 이 기호는 ‘quoted-printable’ 인코딩 과정에서 생기는 것으로, 긴 줄을 강제로 나눌 때 줄이 이어짐을 표시하기 위해 사용됨
  • 이메일 전송 시 CRLF(캐리지리턴+라인피드) 를 줄바꿈으로 쓰는데, 이를 Unix의 NL 로 변환할 때 디코딩 알고리듬이 잘못 작동하면 등호가 남거나 문자가 손실됨
  • 등호는 줄바꿈 외에도 비ASCII 문자(예: =C2=A0) 를 표현하는 데 쓰이며, 잘못된 디코더가 이를 단순 치환해 오류를 유발함
  • 문제의 원인은 버그가 있는 디코딩 로직과 부적절한 변환 처리로, 이메일을 가공한 사람이 기술적으로 미숙했음을 보여줌

이메일 인용문 속 등호(=)의 정체

  • 최근 며칠간 트위터에 옛 이메일 인용문이 다수 공유되며, 문장 끝의 등호 기호가 눈에 띄는 현상 발생

    • 작성자는 이를 코드나 OCR(광학문자인식) 오류로 오해하는 주장들을 반박
    • 실제로는 이메일을 읽기 쉽게 변환한 과정에서 발생한 인코딩 처리 오류
  • 이메일은 과거 단순 텍스트였으나, 긴 줄이나 특수문자를 처리하기 위해 ‘quoted-printable’ 인코딩이 도입됨

    • 긴 줄을 나눌 때 줄 끝에 등호(=)를 붙여 “이 줄은 이어진다”는 의미를 표시
    • 이때 등호 다음에는 CRLF(캐리지리턴+라인피드) 가 붙음

줄바꿈 인코딩과 디코딩 오류

  • 이메일 서버는 CRLF 줄바꿈을 표준으로 사용하지만, Unix 시스템은 NL만 사용

    • 변환 과정에서 한 바이트가 줄어들며, 디코더가 이를 잘못 처리하면 등호가 남거나 문자가 빠짐
    • 예시로, “non- =CRLF cloven”이 잘못 처리되면 “non- loven”처럼 ‘c’가 사라짐
  • 일부 구현체는 줄 끝의 등호를 발견하면 두 문자를 삭제하는 방식으로 처리

    • 이 알고리듬이 Unix 형식 파일에서는 오작동해 등호가 그대로 남는 현상 발생

등호의 또 다른 용도: 비ASCII 문자 인코딩

  • 등호는 줄바꿈 외에도 비ASCII 문자 인코딩에 사용됨

    • 예: “=C2=A0”은 non-breaking space(줄바꿈 방지 공백) 을 의미
    • 이메일 본문에서 들여쓰기나 특수문자 표현 시 자주 등장
  • 작성자는 일부 변환자가 =C2, =A0 등을 단순 치환(search-replace)만 하고, 정상적인 디코더를 사용하지 않은 것으로 추정

기술적 배경과 표준

  • RFC 2045 표준은 quoted-printable 인코딩을 전송용(transport) 으로 정의

    • 수신 후에는 디코딩되어 깨끗한 텍스트로 저장되는 것이 원칙
    • 그러나 실제 구현에서는 이 과정이 생략되어, 줄바꿈 처리 오류가 잦음
  • 예시 코드에서 (quoted-printable-decode-string "he=\nllo")"hello" 로 정상 복원됨

    • 이는 SMTP 서버 맥락에서 CRLF를 가정한 알고리듬을 재사용했기 때문
    • Windows 기반 파일에서는 정상 작동하지만, Unix 기반에서는 실패함

결론

  • 이메일 인용문 속 등호는 quoted-printable 인코딩의 잔재이며,
    줄바꿈 처리와 비ASCII 문자 디코딩의 결함이 결합된 결과
  • 문제의 근본 원인은 부정확한 디코더 구현과 인코딩 변환 실수
  • 작성자는 이를 “기술적 문제이자, 잘못된 처리의 결과”로 요약하며,
    이메일 변환 과정의 세밀한 표준 준수가 필요함을 강조함
Hacker News 의견들
  • 이 글의 주인공은 Lars Ingebrigtsen으로, Emacs의 이메일/Usenet 리더 패키지인 Gnus의 매뉴얼을 쓴 사람임
    그의 매뉴얼은 재치 있고 유익하며, 이메일 파싱에 대해 대부분의 사람보다 훨씬 깊은 이해를 가지고 있음
    매뉴얼은 여기서 볼 수 있음, 또 다른 버전은 이 링크에 있음

    • 그는 매뉴얼뿐 아니라 Gnus 자체의 개발자이기도 함
      내가 오슬로대(UiO)에서 그가 Gnus를 처음 만들던 시절을 기억함
      우리 정보학과 학생들 사이에서 작은 스타 개발자였고, 모두 Emacs와 Gnus를 썼음
  • 이 사건은 “위험할 정도로 아는 사람”의 전형적인 사례임
    이메일이 단순 텍스트가 아니라는 건 알았지만, quoted-printable 디코딩을 단순 치환으로 처리하면 안 된다는 건 몰랐던 것임
    정규식으로 HTML을 직접 파싱하는 버그와 같은 부류로, 처음엔 잘 되다가 나중에 의회 증거물에 ‘=’ 기호가 잔뜩 남는 사태가 생김

    • 이와 관련해 유명한 Stack Overflow 답변을 공유함. HTML을 정규식으로 파싱하면 안 되는 이유를 유머러스하게 설명함
    • 출력이 대체로 읽을 만하니, 아무도 문제를 눈치채지 못하다가 수년 후 의회 증거로 제출될 때야 깨닫게 됨
    • “지금 최고 인력들이 처리 중임”이라는 농담으로 마무리함
  • “메일 서버가 왜 긴 줄을 싫어하냐”는 질문이 있었음

    • SMTP는 라인 기반 프로토콜이라 메시지 본문도 줄 단위로 전송됨
      서버는 헤더를 파싱해야 하므로 단순한 바이너리 블롭으로 다룰 수 없음
      IMAP은 서버가 완전한 파싱을 해야 하고, POP3는 단일 기기용이라 요즘엔 맞지 않음
    • 과거에는 메일을 고정 길이 버퍼로 줄 단위 처리했음
      RFC 821이 줄 길이를 최대 1000바이트로 제한했고, 호환성을 위해 80자 이하로 끊는 게 일반적이었음
      그래서 Base64 인코딩도 76자마다 줄바꿈을 넣음
    • SMTP가 설계될 당시 메모리가 극도로 제한적이었음
      예를 들어 PDP-11은 512KB, VAX-11은 2MB 정도였고, 프로그래머들은 바이트 단위로 메모리를 계산했음
    • SMTP 명령 흐름을 직접 보여주며, HELO, MAIL FROM, RCPT TO, DATA 등으로 통신하는 구조를 설명함
    • 1980년대 대학 네트워크 BITNET을 언급하며, 당시에도 줄 길이 제한이 있었음을 회상함
      관련 문서는 IBM 공식 문서Wikipedia에서 볼 수 있음
  • 처음엔 이 글이 = == === .=. <== ==> <<== ==>> (==) => =~= 같은 연산자 의미에 대한 이야기일 줄 알았음

    • “이건 개미용 Haskell인가?”라는 농담이 달림
    • 하지만 실제 내용이 훨씬 흥미로웠다고 함
  • 나는 개인적으로 이메일 아카이빙 소프트웨어를 직접 만들었음
    20년 넘게 쌓인 .eml 파일의 엣지 케이스 처리가 가장 어려웠음
    개념은 단순하지만 이메일은 놀라울 정도로 복잡함

    • 이메일 표준은 처음부터 새로 만든 게 아니라, 기존 시스템들을 억지로 이어붙여 만든 저주받은 표준
      이메일 주소 유효성 검증도 사실상 불가능에 가까움
    • 콘솔 기반 메일 클라이언트를 만들었는데, 25%는 C++, 75%는 Lua로 UI와 처리를 정의했음
      몇 년간 소수의 사용자가 있었지만, MIME 처리가 가장 큰 고통이었음
  • 내가 흥미롭게 본 건 ‘=’ 기호 자체보다, 그 주변의 문자가 사라지는 현상이었음
    마치 off-by-one 오류처럼, ‘=’을 지우는 대신 실제 텍스트 일부가 사라진 것 같음
    아마 CRLF/LF 변환이 관련 있을지도 모름

    • 원문 기사에서 그 이유를 정확히 설명함
    • 이런 식으로 증거물에서 문자가 사라지는 미스터리가 생김
  • 왜 이런 문제가 지금 나타나는지 궁금했음
    최근 며칠간 사람들이 오래된 이메일을 트위터에 올리고 있는데, 이유가 뭘까 했음

    • 아마 Epstein 관련 이메일 공개 때문일 것 같다고 함
    • 실제로 DOJ가 Epstein 이메일을 추가로 공개했다고 함
  • 어떤 사람은 이 문제의 원인이 Gmail이 아니라 중간 서버의 변환일 가능성을 제기함
    CRLF→LF 변환 외에도, quoted-printable을 두 번 적용하면 ‘=’이 남는 현상이 생기므로, 두 개의 메일 서버가 관여했을 수도 있음

    • 일부 PDF에서 Apple Mail.app의 plist 메타데이터가 보여서, 내부 포맷에서 추출된 것일 가능성이 있음
    • 법적 증거물 수집 과정에서 이런 일이 자주 발생함
      실제로는 비전문 인턴이 단순한 도구로 데이터를 모으고, 여러 번 변환되며 포맷이 망가짐
      원본은 이미 파기되고, 남은 건 형태만 남은 파편 데이터뿐임
    • 종종 이메일을 MS Outlook의 PST 파일로 임포트하면서 이런 문제가 생김
    • 단일 Gmail 덤프가 아니라, 여러 시스템이 “도와준답시고” 데이터를 변형한 결과물 같음
    • 이 가설이 가장 설득력 있어 보인다는 의견도 있었음
  • archive.today의 기사도 같은 quoted-printable 깨짐 현상을 보임
    관련 링크는 pastes.io/correspondHN 스레드

  • Outlook에서 다운로드한 메일을 볼 때, quoted-printable을 자동으로 풀어주는 .eml 뷰어가 있으면 좋겠다고 함