평판 나쁜 3개(chat·mail.rinda / send.grinda) → 18개 워밍업 도메인 분산 · 발송·답장·웹훅 코드 + 실데이터 검증
📊 beta production🗓 2026-06-15⚙ 발송·답장·웹훅 코드 60+파일🔍 18도메인 수신 실증
✓판정: 계획은 타당하다 (조건부)
발송 분산
코드 지원 ✓
답장 스레드 매칭
도메인 무관 ✓
18도메인 수신
실증됨 ✓
진행중 캠페인
절차 필요 ⚠
가장 큰 위험이 실증으로 해소 — 18개 워밍업 도메인은 이미 각 102~176건 답장을 수신 중(6/5~6/15). MX/SES Receipt Rule이 작동한다는 직접 증거 = "수신 인프라 누락으로 답장 유실" 위험 없음.
"랜덤"이 아니라 더 안전한 sticky 해시 — 코드는 SHA256(리드 이메일) % 풀크기로 분배. 같은 바이어는 항상 같은 도메인, 1·2·3차 후속도 같은 주소. 한 바이어가 18개 도메인에서 받는 혼란은 구조적으로 발생 안 함.
스레드/시퀀스 매칭은 발신 도메인과 완전 무관 — SES 발신의 message_id가 @amazonses.com 고정이라 도메인을 바꿔도 In-Reply-To 매칭 키 불변.
진행중 enrollment는 자동으로 안 바뀜 — 발신계정이 sticky 고정. reallocate-sender-pool.ts --commit 실행이 세트로 필요(미발송분만 재분산, 발송완료분은 보존).
옛 3개 도메인 즉시 폐기 금지 — in-flight 시퀀스 답장이 그리로 옴. is_active=false로 발송만 끊고 수신은 grace 유지.
★핵심 증거: 18개 도메인 수신 실증
코드상 가장 치명적 위험은 "발송은 되는데 그 도메인 MX/Receipt Rule이 없어 답장이 시스템에 진입조차 못 하고 로그도 없이 완전 유실"이다(코드에 수신 도메인 검증·계측 부재). 그러나 실데이터가 18개 전부 수신 작동을 증명한다.
도메인
최근 답장 수신
건수(누적)
수신기간
ask·intro·note·knock·letter
142~176
6/5~6/15
ping·meet·sync·hey·share·memo·post·voice
128~138
6/5~6/15
say·talk·reach·hi·brief
102~116
6/5~6/15
결론: 18개 도메인 모두 MX/Receipt Rule이 살아있고 답장이 정상 적재되고 있다. 계정도 각 2개씩 전부 verified + active. 수신 인프라 측면에서 추가 셋업 없이 즉시 분산 가능.
1발송 코드 — from 결정 & 분산
항목
동작
근거
from 주소
계정 email_address에 고정(도메인=계정 1:1). 발송 시점 동적선택 없음
send-email.ts:766
리드 분배
SHA256(리드 이메일) % 풀크기 sticky 해시. 랜덤·라운드로빈 아님
mailbox-rotation.service.ts:18
스텝 일관성
1·2·3차 후속 전부 같은 발신주소(enrollment sender 상속)
sequence-email-loader.worker.ts:165
신규 분산
18계정을 sequence_email_accounts에 넣으면 자동 18-way
getMailboxPoolForSequence
진행중 enrollment
자동 안 바뀜 — user_email_account_id 고정. 재할당 필요
sender-pool-reallocate.service.ts:123
레이트리밋
SES/SendGrid는 daily cap 면제 → 워밍업 보호 위해 daily_limit 명시 설정 필요
send-email.ts:469
재할당 메커니즘:reallocate-sender-pool.ts는 ① 발송완료 enrollment 보존(스레드 일관성) ② 미발송분만 새 18개 풀로 재해시 ③ terminal(stopped/bounced 등) skip. 기본 DRY-RUN, --commit 필요. paused→resume 시 자동 호출.
2답장·웹훅 수신 코드
수신 진입점 3개
경로
수신 대상
비고
SES Inbound Consumer
Receipt Rule → S3 replies/ raw MIME
단일 버킷/prefix polling. 도메인 분기 없음 — 18개 다 같은 prefix로 떨어지면 자동 처리
각 계정 daily_limit 설정 — SES cap 면제이므로 워밍업 단계에 맞춰 보수적으로. 점진 ramp.
옛 3개 도메인 발송 차단 — rinda_managed_sending_domains.is_active=false(chat은 이미 infinite 전용). MX·계정 row는 유지. ⚠️ user_email_accounts row를 절대 DELETE하지 말 것 — status='inactive'로만(옛 주소 수신 영구 보존, §6 참조).
계측 추가 — 도메인별 발송 대비 답장 회수율 모니터링(현재 유실 시 로그조차 없음). 누락 조기 감지.
⚑옛 주소로 오는 메일 — 무엇이 유실을 부르나
질문: "평판 나쁜 도메인을 전부 교체하면, 바이어가 옛 주소로 직접 보내는 메일을 웹훅이 못 잡지 않나?" — 코드 직답
결론: 웹훅 계정 귀속 쿼리는 emailAddress = to_email단 하나만 본다. status·deleted_at·is_verified 필터가 전혀 없다(deleted_at 컬럼은 스키마에 존재조차 안 함). → 옛 계정 row를 DELETE하는 것만이 유실을 일으킨다. 비활성화·풀 제거·발송차단은 수신에 무영향.
귀속 쿼리 원문 (webhook.service.ts:269-290)
조건
존재?
의미
emailAddress = toEmail
유일 조건
주소 1:1 매칭(글로벌 unique index)
status = 'active'
없음
inactive여도 매칭됨
deleted_at IS NULL
없음(컬럼 자체 부재)
soft-delete 미구현
매칭 0건 시
return {isReply:false}
emails 적재도 없이 완전 유실
옛 계정 정리 방식별 영향
정리 방식
수신 귀속
결과
(a) sequence_email_accounts에서만 제거
정상
웹훅은 이 테이블 안 봄
(b) status='inactive'
정상
status 필터 없음
(c) 발송 도메인 is_active=false
정상
발송만 차단, 수신 독립
(d) user_email_accounts row DELETE
깨짐
옛 주소 메일 통째 유실
왜 중요한가 — 옛 주소는 아직 활발히 수신 중
옛 도메인
inbound 7일
inbound 30일
in-flight active enrollment
mail.rinda.ai
217
1,337
246,687
chat.rinda.ai
154
2,699
13,898
send.grinda.ai
27
245
2,209
in-flight enrollment(특히 mail.rinda 24.7만)이 앞으로도 계속 발송→답장 유입. 옛 주소 수신 보존은 선택이 아니라 필수.
헤더 있는 답장 vs 직접 발신 — 둘 다 같은 게이트
스레드 매칭(message_id)이 성공해도 계정 귀속(to_email)이 단일 상위 게이트다. 귀속 0건이면 fallback에 도달조차 못 하고 return. 헤더 없는 직접발신도 to_email 귀속을 먼저 거친 뒤에야 addr/subject fallback을 탄다. 결국 옛 주소 row만 살아있으면 답장·직접발신 모두 잡힌다.
안전한 정리 공식: ① MX/Receipt Rule 유지 ② user_email_accounts row는 DELETE 금지, status='inactive'로만 ③ 발송 도메인 is_active=false + 풀 제거는 자유. row만 안 지우면 옛 주소 수신은 영구히 안전. (단 글로벌 unique index상 그 주소를 새 계정으로 재등록은 불가.)
!코드의 구조적 빈틈 (별도 개선 권고)
발송 SSOT와 수신 인프라 drift 가능 — rinda_managed_sending_domains에 도메인 INSERT하면 발송은 즉시 시작되나, 그 도메인 MX/Receipt Rule 존재를 코드가 검증하지 않음. 풀 추가 전 수신 사전검증 게이트 부재.
유실 무계측 — 수신 인프라 누락 시나리오(a)는 로그·DB·격리(failed/) 어디에도 흔적 없음. CLAUDE.md preflight ⑦(오작동 감지) 위반 소지.
reply_classification 99.5% null의 근본 — 도메인 문제가 아니라 스레드 매칭 실패로 email_replies row가 안 생기는 것. 수신 누락이 누적되면 분류율도 동반 하락.