본문으로 건너뛰기

LLM이 회신 제목을 생성해 이메일 스레드가 분리된 사례

회신 제목을 LLM에 맡기면 Gmail에서 스레드가 분리되므로 원본 제목을 정규화하고 Message-ID를 보존해야 한다.

이 요약은 AI가 원문을 분석해 생성했습니다. 정확한 내용은 원문 기준으로 확인하세요.

TL;DR

글쓴이는 LLM을 이메일 회신 파이프라인에 넣었을 때 발생한 스레드 분리 문제의 원인과 해결을 기술했다. 첫째는 워크플로우로 Subject와 Message-ID가 누락되어 In-Reply-To/References 헤더가 빠진 점이고, 둘째는 모델에게 replySubject를 위임해 원본 제목이 보존되지 않은 점이었다. 해결책은 제목 정규화 함수를 통해 'Re: 원본제목'을 생성하고 Message-ID를 파이프라인 전구간에서 유지하며 승인 전에 실제 발송 제목을 계산하게 하는 방식이었다.

섹션별 상세

웹 사이트 스튜디오에 LLM 기반 에이전트를 접목해 리드 이메일에 자동 초안 생성과 인간 승인 단계를 넣은 파이프라인에서, 회신이 수신자 Gmail에 새로운 대화로 도착하는 문제가 발견됐다. 파이프라인은 SES가 메일을 받아 S3에 저장하고 Lambda가 파싱해 ingestion 서비스로 전달하며 durable workflow가 초안을 만들고 승인 뒤 발송하는 구조였다. 로그에는 전송·배달·수신 이력이 정상적으로 남았지만 스레드가 이어지지 않는 증상이 발생해 원인을 추적했다.
첫 번째 버그는 수집 단계에서 webhook이 원본의 Subject와 RFC822 Message-ID를 데이터베이스에 저장했지만 워크플로우 시작 시 이 값들을 전달하지 않아 발신 이메일에 In-Reply-To와 References 헤더가 빠져나간 점이었다. 결과적으로 전송된 메일은 프로토콜적 연결 고리가 없어 Gmail이 스레드를 묶을 근거를 잃었다. 이 문제는 파이프라인의 데이터 전파 결여이며 발신 페이로드에 Message-ID를 통째로 통과시키는 것으로 해결 가능하다는 점이 확인되었다.
두 번째 버그는 모델 역할 분배의 오류로, 응답 초안 JSON 스키마에 replySubject 필드를 포함시켜 LLM(Claude)이 회신 제목을 생성하도록 했다는 점이다. 프롬프트에는 스레드의 원본 Subject가 포함되지 않았으므로 모델은 적절하지만 새로운 제목을 생성했고 그 제목이 실제 발송 제목으로 사용되면 Gmail에서 다른 대화로 처리됐다. 본질적으로 모델에게 '프로토콜 값'을 위임한 설계 실수였고, 모델은 요청받은 대로 텍스트를 생성했을 뿐이다.
Gmail은 References/In-Reply-To 헤더 외에도 Subject 헤더의 일치 여부를 별도 조건으로 스레딩에 사용한다는 점을 글쓴이가 확인했다. 즉 올바른 References 헤더가 있어도 Subject가 달라지면 새 대화가 생성되므로 회신 제목을 임의로 바꾸면 스레드가 분리된다. 따라서 스레드 보존을 위해서는 헤더 보존과 함께 원본 제목의 정규화 및 보존이 필수적이라는 클라이언트별 요구사항이 드러났다.
근거
  • Gmail은 References/In-Reply-To를 요구하는 것 외에 Subject 헤더가 일치해야 같은 스레드로 묶는다. 글쓴이는 Gmail의 스레딩 문서의 세부 규칙을 인용하며, References/In-Reply-To와 별도로 Subject 헤더 일치를 요구한다고 밝힌 부분을 근거로 제시했다.
해결책은 회신 제목을 모델이 생성하도록 맡기는 대신 프로토콜 로직으로 처리하고, Message-ID를 파이프라인 전구간에서 유지하며 승인 인터페이스에 실제 발송 제목을 보여주는 것으로 구성했다. 구체적으로 원본 제목에서 모든 회신·전달 접두사를 stripReplyPrefixes로 정규화해 'Re: 원본제목' 형태로 만들고, SES v2의 Headers 필드로 In-Reply-To와 References를 전달하도록 페이로드를 구성했다. 또한 승인 게이트 전에 제목을 계산해 운영자가 실제 발송 제목을 승인하게 하여 승인 후 재작성으로 인한 미검증 변경을 차단했다.
javascript
/** Strip any stack of reply/forward prefixes ("Re:", "RE:", "Fwd:", ...). */
function stripReplyPrefixes(subject: string): string { return subject.replace(/^(\s*(re|fwd?|aw|sv)\s*(\[\d+\])?\s*:\s*)+/i, "").trim();}
export function threadReplySubject(original: string | null | undefined, fallback: string): string { const stripped = original ? stripReplyPrefixes(original) : ""; return stripped ? `Re: ${stripped}` : fallback;}

원본 이메일의 Subject에서 여러 언어와 중첩된 회신/전달 접두사를 제거해 단일한 'Re: 원본제목' 형태로 정규화하는 코드다. 이 함수는 모델이 생성한 임의의 제목 대신 프로토콜적으로 올바른 회신 제목을 보장하기 위해 사용된다. 다국어 접두사와 Re[2]: 같은 번호 표기까지 제거해 Gmail의 제목 일치 규칙을 만족시킨다.

json
Content: { Simple: { Subject: { Data: subject }, Body: { Text: { Data: text }, Html: { Data: html } }, Headers: [ { Name: "In-Reply-To", Value: inboundMessageId }, { Name: "References", Value: inboundMessageId }, ], },},

SES v2 형식으로 발송 페이로드에 In-Reply-To와 References 헤더를 직접 포함시키는 예시 JSON이다. 이 필드를 통해 수신 메시지의 Message-ID가 발신 이메일의 헤더로 유지되어 RFC 기반의 스레딩 메타데이터가 전달된다. 파이프라인 전 구간에서 inbound Message-ID를 보존해야 Gmail과 다른 클라이언트에서 스레드 연결이 유지된다.

근거
  • SES v2의 Simple Content 형식은 Headers 필드를 통해 In-Reply-To와 References를 포함시킬 수 있고 @aws-sdk/client-sesv2 3.1057에서 지원된다. 본문에는 SES v2의 Content.Simple.Headers 예시 JSON과 함께 해당 기능이 오래전부터 지원되었다는 언급과 사용된 SDK 버전 메모가 있다.

용어 해설

In-Reply-To 헤더(In-Reply-To)
이메일 프로토콜(RFC 5322)에서 회신 메시지가 어떤 원본 메시지에 대한 것인지 식별하기 위해 사용하는 헤더로, 보통 원본의 Message-ID를 값으로 포함한다. 이메일 클라이언트와 서버는 이 값으로 메시지 간 관계를 연결하여 스레드를 구성하거나 참조 체인을 따라간다.
References 헤더(References)
회신 메시지가 참조하는 이전 메시지들의 Message-ID 목록을 순서대로 적는 헤더로, 스레드 전체의 참조 체인을 유지한다. 다수의 중첩된 회신을 추적할 때 클라이언트가 스레드 구성 결정을 내리도록 돕는 프로토콜 필드다.
Message-ID
각 이메일 메시지에 고유하게 붙는 식별자이며 RFC 5322 규격에 따라 포맷된다. 회신이나 References/In-Reply-To 헤더는 보통 이 Message-ID 값을 사용해 원본과의 관계를 연결한다.
제목 기반 스레딩 규칙(Subject threading)
특정 이메일 클라이언트(Gmail 등)는 References/In-Reply-To 외에 Subject 헤더 일치 여부를 추가 조건으로 사용해 메시지를 같은 스레드로 묶는다. 따라서 헤더가 정확해도 Subject가 변경되면 새 대화로 분리될 수 있다.
회신·전달 접두사 처리(Reply/forward prefixes)
각종 이메일 클라이언트가 회신 또는 전달 시 제목 앞에 붙이는 Re:, Fwd:, AW:, SV: 또는 Re[2]: 같은 접두사를 정규화해야 원본 제목을 정확히 비교할 수 있다. 다국어·중복 표기·번호 표기의 변형을 제거하는 전처리가 필요하다.

기술

  • Claude
  • SES
  • SES v2
  • @aws-sdk/client-sesv2 3.1057
  • AWS Lambda
  • S3

활용 사례

  • 리드 이메일에 대해 LLM이 초안을 생성하고 사람이 승인한 뒤 발송하는 자동응답 파이프라인
  • 웹폼으로 들어온 최초 메시지에 대해 모델이 제목을 생성해 초기 이메일을 구성하는 경우
AI 분석 전체 내용 보기

AI 요약 · 북마크 · 개인 피드 설정 — 무료

출처 · 인용 안내

원문 발행 2026. 08. 06.수집 2026. 08. 06.출처 타입 RSS

인용 시 "요약 출처: AI Trends (aitrends.kr)"를 표기하고, 사실 확인은 원문 보기 기준으로 진행해 주세요. 자세한 기준은 운영 정책을 참고해 주세요.