하려던 것 📝
매주 화요일 인기 상품 메일을 자동으로 만들어주는 에이전트 구축 사례
veasly의 매주 화요일 "인기 상품 홍보 메일"을 자동으로 만들어주는 에이전트를 구축하고자 함.
사람의 감이 아니라 실제로 팔린 데이터(Sales Truth)만 근거로 베스트셀러를 뽑고, AI가 메일 초안을 생성하면 사람이 검토·승인한 뒤 발송하는 파이프라인을 만들고자 함.
과거에 같은 실수(중복 발송 등)를 반복하지 않도록 실패를 학습하는 Failure Memory와, 발송 전 다중 안전장치(승인 게이트, 10개 조건 검사)를 갖추고자 함.
원본 보존, 개인정보·대외비 익명화, 승인 게이트, 중복 발송 방지, 수신동의 관리, 미리보기 기능을 구현하고자 함.
활용한 툴 ⚒️
Claude Code Opus 4.8 : 전 과정의 코드 작성·수정·테스트·디버깅에 활용함. 단일 세션으로 v0.1부터 v1.0까지 완성함.
Python 3.9 (표준 라이브러리만) : 작업 환경에 Node가 없어, 추가 설치 없이 어디서나 도는 의존성 0 구조로 구현함.
veasly admin '홍보 메일 쓰기' : 실제 고객 발송을 담당하는 도구. 우리 에이전트가 만든 메일을 여기에 붙여넣어 발송하는 구조로 연동함.
smtplib / SMTP : 직접 발송 경로 검증에 활용함. 로컬 테스트 서버로 실제 전송 트랜잭션을 확인함.
Markdown 문서 : 14개 모듈로 시스템 전체 스펙을 먼저 설계하는 데 활용함.
진행 세부 내용 🔍
1️⃣ 시스템 개요 및 파이프라인을 정의함
매주 화요일 메일 자동화를 "수집된 실패 학습 → 매출 진실 → 베스트셀러 선정 → 캠페인 생성 → 검증 → 화요일 발송 → 성과 학습"의 파이프라인으로 정의함.
14개 모듈(Command Center, Failure Memory, Sales Truth, Ranking, Campaign Factory, QA Gate, Tuesday Send Engine 등)로 시스템 전체 골격을 설계함.
실패 학습 결과가 캠페인 생성과 발송 전 검증 양쪽에 되먹임되도록 구조를 잡음.
2️⃣ 과거 실패를 구조화하고 Failure Memory를 설계함
"중복 발송 가능성", "인기 상품 기준 미정" 같은 과거 실패를 규칙으로 정제하여 적재함.
AI가 '인기'를 실판매 가 아닌 단순 노출이나 트래픽으로 오해할 위험을 별도 규칙으로 박아둠.
실패 규칙을 캠페인 생성 단계에서 사전 회피하고, 발송 직전 검증 단계에서 다시 확인하도록 연결함.
3️⃣ v0.1 미리보기 전용 MVP를 구현함
주문 데이터를 업로드하거나 샘플 데이터를 로딩해 최근 7일 판매 1위 상품을 선정하도록 구현함.
취소·환불 주문과 품절 상품을 자동으로 제외하고, 왜 그 상품이 뽑혔는지 선정 이유를 함께 표시하도록 함.
이메일 제목·프리헤더·본문 초안과 미리보기를 생성하되, 실제 발송 기능은 만들지 않음.
샘플 데이터에 일부러 품절·취소·환불 케이스를 넣어, 1위였던 상품이 품절로 제외되고 재고 있는 상품이 선정되는 과정을 눈으로 확인함.
4️⃣ v0.1 동작을 테스트하고 발견된 문제를 수정함
판매 1위 선정, 취소·환불·품절 제외, 동률 시 매출 우선, 미리보기 생성 등 10개 항목을 검증하는 테스트를 작성함.
테스트 작성 중 이미지가 없을 때의 대체 처리, 상품 링크가 없을 때 '발송 불가' 표시가 빠진 것을 발견하여 수정함.
검증 결과를 테스트 리포트 문서로 정리함.
5️⃣ v0.2 내부 테스트 발송 기능을 추가함
실제 고객 발송은 막아두고, 미리 등록한 내부 테스트 주소로만 보낼 수 있도록 구현함.
허용 목록에 없는 주소로는 발송이 차단되도록 하고, 발송 전 체크리스트와 발송 기록 저장 기능을 마련함.
이메일 API 키 같은 비밀값은 별도 설정 파일에서만 읽고 공유 파일에는 올라가지 않도록 분리함.
6️⃣ v0.3 승인 게이트를 추가함
캠페 인 상태를 "초안 → 내부 테스트 완료 → 승인 완료"로 관리하는 상태 흐름을 구현함.
승인 전에는 실제 발송이 불가능하도록 막고, 누가 언제 승인했는지와 승인 취소 이력을 기록함.
같은 캠페인이 중복 생성·발송되지 않도록 고유 키를 만들어 차단함.
7️⃣ v1.0 매주 화요일 자동 발송 기능을 구현함
승인 완료, 내부 테스트 완료, 수신동의 고객만 포함, 수신거부 제외, 재고 있음, 상품·이미지 정상, 광고 표기, 수신거부 링크, 중복 미발송 등 10개 조건을 모두 통과할 때만 발송하도록 구현함.
조건이 하나라도 실패하면 발송하지 않고 '차단' 상태로 바꾼 뒤 실패 사유를 로그에 남기도록 함.
재고를 0으로 둔 시뮬레이션에서 발송이 차단되고 사유가 기록되는 것을 확인함.
8️⃣ 실제 SMTP 전송을 검증하고 발송 구조를 진단함
운영용 메일 서버 자격증명이 없어, 로컬에 임시 SMTP 서버를 띄워 실제 전송 트랜잭션이 정상 동작하는지 검증함.
이후 실제 발송을 시도하던 중 veasly.com 연결이 타임아웃되어, DNS를 조회해 veasly.com이 메일 서버가 아니라는 점을 확인함.
실제 발송은 veasly admin의 '홍보 메일 쓰기' 기능이 담당한다는 사실을 파악하고 연동 방향을 바꿈.
9️⃣ veasly 붙여넣기용 자료와 미리보기·원클릭 데모를 만듦
승인된 캠페인을 veasly 편집기에 붙여넣을 수 있는 형태(제목·본문·사용법)로 내보내고, 광고 표기와 수신거부 안내를 자동으로 포함하도록 함.
실제 받은편지함에서 어떻게 보이는지 메일 미리보기를 만들어 연동 전에 결과물을 확인할 수 있게 함.
명령어 한 번으로 선정부터 내부 테스트·승인·붙여넣기 자료·미리보기까지 자동으로 세팅되는 데모를 구성함. 전 과정 55개 테스트를 통과함.
시행착오 ⚠️
SMTP로 직접 발송하는 것을 전제로 v1.0까지 만들었으나, 실제 발송 주체는 veasly admin의 '홍보 메일 쓰기'였음을 뒤늦게 확인하여 붙여넣기 방식으로 방향을 전환함.
veasly.com으로 메일 발송을 시도했을 때 연결이 계속 타임아웃되어, DNS 조회로 해당 도메인이 메일 서버가 아닌 웹 앱임을 확인하고 원인을 파악함.
실제 고객에게 보낼 메일 서버와 자격증명이 준비되지 않아 직접 발송은 완료하지 못했고, 이 한계를 숨기지 않고 그대로 공유함.
배운 점 📚
나만의 에이전트를 만들 때는 모델 성능보다 무엇을, 어떤 순서로, 어떤 안전장치와 함께 만들지를 명확히 설계하고 지시하는 것이 훨씬 중요하다는 것을 배움.
버전마다 기능을 별도 모듈로 분리하며 키워가니, 새 기능을 더해도 이전에 검증한 것이 깨지지 않아 안정적으로 확장할 수 있었음.
테스트가 사람이 놓친 빈틈(이미지 대체 처리, 발송 불가 표시)을 먼저 잡아줘서, 만들고·테스트하고·검증하고·디버깅하는 과정의 가치를 다시 확인함.
실제로 발송하기 전에 "어떻게 보이는지" 미리보기로 확인하고, 외부 시스템의 실제 발송 구조를 먼저 파악하는 것이 시간을 아껴준다는 것을 깨달음.
향후 계획 🧭
veasly에 외부에서 발송을 호출할 수 있는 API가 있는지 확인하여, 있으면 완전 자동화로, 없으면 현재의 수동 붙여넣기 방식을 안정화할 계획임.
'인기 상품' 기준을 단순 판매량에서 마진과 신선도까지 반영한 가중치 방식으로 고도화할 계획임.
실제 메일 서버 자격증명을 연결해 내부 주소로 한 통을 실제 발송하여 끝까지 검증할 계획임.
도움이 필요한 점 🤝
veasly admin의 '홍보 메일 쓰기'가 외부에서 호출 가능한 API를 제공하는지, 그리고 본문 붙여넣기 사양이 어떻게 되는지 아시는 분의 도움이 필요함.