응답 및 웹훅
수신자가 보내오는 모든 것 — 투표, 폼 제출, 평점, 스핀 — 은 프로젝트별로 수집됩니다. 이는 두 가지 방식으로 여러분에게 전달됩니다: 대시보드의 수신자별 응답 화면, 그리고 도착하는 즉시 각 인터랙션을 여러분 자신의 엔드포인트로 전송하는 선택적 웹훅입니다.
대시보드의 수신자별 응답
대시보드 → 해당 이메일 → 응답을 여세요. 이메일이 수집한 모든 인터랙션은 수신자별로 그룹화되고 프로젝트의 데이터 소스와 연결됩니다. 각 그룹은 누가 응답했는지 — 이메일 주소와 해당 행의 다른 필드들 — 와 함께 무엇을 했는지 — 어떤 블록, 어떤 동작, 제출된 값, 그리고 언제 — 를 보여줍니다.
귀속은 라이브 뷰 링크를 보호하는 것과 동일한 서명된 토큰을 통해 이루어집니다. 이메일이 데이터 소스로 개인화되면 각 수신자의 링크는 자신의 행에 묶인 토큰을 지니게 되고, 유효한 토큰과 함께 도착한 인터랙션은 그 행으로 귀속됩니다. 토큰 없이 도착한 인터랙션(예: 개인화 없이 발송된 이메일의 투표)도 여전히 집계되며 — 별도의 익명 그룹에 나열됩니다.
원시 이벤트 목록은 페이지네이션됩니다(최신순): 최신 페이지를 불러온 뒤에는 더 보기 동작으로 이전 이벤트를 가져올 수 있습니다. 아래의 나머지 항목들 — 집계, 히스토그램, 퍼널과 추이 — 은 이 페이지네이션의 영향을 받지 않습니다. 이들은 미리 계산되며 항상 프로젝트의 전체 기록을 다룹니다.
주문, 이행 및 환불
상품 블록이 있는 모든 프로젝트는 응답 페이지에 주문 표를 갖게 됩니다 — 체크아웃 한 건당 한 행으로, 구매자, 금액, 상태, 주문 시각이 표시됩니다.
- 결제가 완료되는 순간 구매자에게 자동으로 이메일이 발송됩니다: 디지털 상품이라면 배송 콘텐츠를, 실물 상품이라면 이행 준비 중이라는 확인 메일을 받습니다.
- 실물 주문의 경우, 배송을 마치면 이행 완료로 표시를 클릭하세요 — MailInApp이 배송 자체를 처리하지는 않지만, 스위치를 전환하는 순간 구매자에게 배송 알림 메일을 보냅니다.
- 결제 완료된 주문에서 환불을 클릭하면 연결된 Stripe 계정을 통해 결제를 취소하며, 구매자에게 환불 확인 메일이 발송됩니다. 마지막 재고가 팔리는 순간 판매가 완료되어 버린 경우에도 동일한 메일이 자동으로 발송됩니다 — MailInApp은 조용히 초과 판매하는 대신 구매자에게 환불합니다.
- 구매자에게 연락은 해당 주문의 맥락이 미리 채워진 지원 티켓을 엽니다 — 구매자에게 직접 무언가를 물어보는 가장 빠른 방법입니다.
목적 기반 핵심 지표
프로젝트에 목적(설문조사, 프로모션, 뉴스레터 또는 이벤트)이 설정되어 있으면, 응답 페이지는 그 목적이 가장 중요하게 여기는 하나의 숫자로 시작합니다: 설문조사라면 응답률, 프로모션이라면 참여한 수신자 수, 뉴스레터와 이벤트라면 추적된 열람 수입니다. 트랜잭션 프로젝트와 목적이 설정되지 않은 프로젝트는 이를 건너뛰고 곧바로 아래의 퍼널과 집계로 넘어갑니다. 페이지 제목 옆의 드롭다운에서 언제든 목적을 바꾸거나 지울 수 있습니다 — 이는 어떤 숫자가 강조되는지에만 영향을 줄 뿐, 기록되는 내용에는 전혀 영향을 주지 않습니다.
CSAT, CES 및 NPS 집계
모든 평점 블록은 수신자 목록 위에 집계를 얻습니다: 응답 수, 평균, 그리고 히스토그램(평균 뒤에 숨은 분포 — 4.1이라는 평균은 모두 4점인지, 5점과 1점이 섞인 것인지 알려주지 않습니다). NPS 형태의 블록은 단순 평균 대신 추천자/중립자/비추천자 수와 −100~100 점수를 보여줍니다. 응답 분포 분석은 투표 블록에 대해 선택지별로 동일한 정보를 제공합니다.
참여 퍼널(발송됨 → 열람됨(추정) → 응답함)이 집계들 위에 표시됩니다. 블록별 응답 추이 차트(일간 또는 주간 단위)는 시간에 따른 평균을 보여줍니다 — 반복되는 설문조사의 가치는 한 번의 스냅숏이 아니라 추이선에 있습니다. 이는 블록에 최소 두 개의 구간 데이터가 있어야 렌더링됩니다.
설문 문항별 집계
모든 폼 블록은 평점 및 투표 블록과 동일한 방식으로 문항별 집계를 얻습니다. 객관식, 체크박스, 선형 척도, 별점 문항은 선택지별 개수의 막대 차트를 얻고, 자유 서술형 문항(단답형, 장문형, 이메일, 숫자, 전화번호, 날짜)은 응답 수와 몇 가지 샘플 답변을 얻습니다. 다중 페이지 설문조사도 단일 페이지 설문조사와 동일하게 집계됩니다 — 제출은 모든 페이지가 완료되어야만 카운트되므로, 중도에 포기한 설문조사가 부분 응답으로 표시되는 일은 없습니다.
이런 투표, 평점, 설문 문항 결과는 그것으로 끝이 아닙니다 — 이 중 무엇이든 차트 블록을 "캠페인 응답"에 연동하기만 하면 향후 이메일 안에 수동 재입력 없이 바로 표시할 수 있습니다. 차트를 실제 데이터에 연동하기를 참고하세요.
과제 및 성적표
완료 또는 제출이 하나 이상 있는 모든 과제 블록은 성적표 표 위에 통계 카드(완료, 지각 완료, 제출)를 얻습니다. 표는 학생당 한 행, 과제당 한 열로 구성되며, 초록색으로 "완료" 또는 제출된 답변을 보여주고, 블록의 마감일 이후에 도착했다면 빨간색으로 표시합니다. 아직 응답이 없는 과제는 표를 어지럽히지 않습니다. 다른 모든 집계와 마찬가지로 이는 미리 계산되며 프로젝트의 전체 기록을 다루고, 두 CSV 내보내기 모두 블록별 과제 열을 포함합니다.
클릭 히트맵
집계 아래에는 클릭 히트맵이 일반 링크가 있는 모든 블록 — 버튼, 링크가 걸린 이미지, 소셜 아이콘 — 을 클릭 수로 순위를 매기며, 상대적인 볼륨에 맞춰 막대 길이와 강도를 조정해 보여줍니다. 무엇이 집계되고 무엇이 집계되지 않는지는 클릭이 추적되는 방식을 참고하세요.
스크롤 깊이 퍼널
스크롤 깊이 퍼널은 라이브 뷰 방문자 중 몇 퍼센트가 페이지의 25/50/75/100% 지점에 도달했는지를 보여줘, 사람들이 일찍 이탈하는지 끝까지 읽는지 알 수 있게 합니다. 이는 오직 호스팅된 라이브 뷰 방문만 반영하며 발송된 이메일 자체는 반영하지 않습니다 — 이유는 스크롤 깊이를 참고하세요.
A/B 테스트 및 자동 승자 선정
두 개 이상의 변형으로 발송하면(발송 참고) 응답 페이지에 변형 비교가 추가됩니다: 각 변형의 열람률, 클릭률, 응답률을 나란히 보여주고, 테스트에 사용한 지표를 기준으로 현재 선두를 표시합니다. 모든 수신자는 이메일 주소를 기준으로 결정론적으로 변형에 배정되므로, 재발송과 재시도가 있어도 누가 어떤 변형을 봤는지 뒤섞이지 않습니다. 결과는 프로젝트 기준으로 누적되며, 가장 최근 실행뿐 아니라 지금까지 실행한 모든 A/B 발송을 포괄합니다.
변형은 제목 문구에만 국한되지 않습니다 — 발신자 아이디나 프로젝트 콘텐츠 전체를 바꿀 수도 있습니다. 콘텐츠가 다른 변형 자체의 투표/퀴즈/RSVP 응답과 열람은 이 비교에 합쳐지지 않고 해당 프로젝트 고유의 응답 페이지에서 추적됩니다. 인터랙션 검증이 제출을 렌더링된 정확한 프로젝트에 묶기 때문입니다. 비교 패널은 오해의 소지가 있는 0을 보여주는 대신 해당 페이지로 연결됩니다.
자동으로 승자 선정하기는 수동 A/B 테스트를 스스로 실행되는 테스트로 바꿔줍니다. 테스트 비율(예: 목록의 20%를 변형별로 나누어 발송), 결정까지 기다릴 시간, 그리고 결정 기준 지표(열람, 클릭, 이메일 내 응답, 또는 매출)를 선택하세요. 이메일 내 응답(투표/퀴즈/RSVP 완료)이 권장되는 기본값입니다. 열람 추적과 달리 Apple의 메일 개인정보 보호 기능의 영향을 받지 않기 때문입니다.
대기 시간이 지나면 MailInApp은 수신자 1인당 비율이 가장 좋은 변형을 선택합니다. 이는 절대 원시 합계가 아니므로, 테스트에서 단순히 더 많은 사람에게 발송된 변형이 볼륨만으로 승자처럼 보일 수 없습니다. 승자는 초기 테스트에서 제외되었던 나머지 전원에게 발송됩니다. 결과가 동점이거나 표본이 너무 작다면 MailInApp은 변형 1로 대체하고 이를 명확히 표시합니다 — 절대 거짓 승자를 선언하지 않습니다. 응답 페이지의 상태 배너는 테스트가 정확히 어떤 상태인지 보여줍니다: 아직 결정 중, 결정됨, 동점, 또는 표본 부족.
발송 시점 최적화
Pro 이상에서 사용할 수 있습니다. 발송의 모든 대상이 한 번에 나가는 대신, 각 수신자의 최적 시간에 발송은 각 연락처 자신의 열람 시간 기록 — UTC 기준으로 하루 중 실제로 여러분의 메일을 가장 많이 열어본 시간대 — 을 살펴봅니다. 그 시간이 될 때까지 메시지를 보류합니다. 신뢰할 만한 신호를 낼 만큼 충분한 열람 기록이 없는 사람은 그대로 즉시 발송으로 넘어갑니다.
이는 수동 발송, 예약 발송, 여정의 자체 발송 단계에도 동일하게 적용됩니다. 예약 발송은 신호가 없는 사람에게는 여전히 설정된 시각에 발송하며, 이는 최적화 이전 동작과 동일합니다. 지연된 수신자는 승자가 결정될 때까지 집계되지 않으므로, 이는 현재 같은 발송에서 자동 승자 테스트와 함께 사용할 수 없습니다.
필드별로 나누어 보기
분류 기준을 사용하면 데이터 소스의 어떤 필드로든 동일한 집계를 나눌 수 있습니다 — 상담원별 평균 CSAT, 플랜별 NPS 등. 발송 이후 행이 삭제되었거나 줄어든 수신자는 **(알 수 없음)**으로 분류됩니다. 자유 서술형 필드가 20개를 초과하는 고유 값을 만들어내면, 가장 작은 그룹들은 화면이 폭발하지 않도록 후행 기타 그룹으로 접힙니다.
CSV 내보내기
응답 페이지의 CSV 다운로드는 수신자당 한 행으로 구성된 넓은 파일을 내보냅니다: 모든 데이터 소스 필드, 첫 열람 시간, 그리고 인터랙티브 블록당 한 열(해당 질문으로 헤딩됨)입니다. 후속 질문의 답변은 별도의 <질문> — 후속 열을 얻습니다. 두 번째 원시 이벤트 내보내기는 긴 형식을 원하는 분석가를 위해 이벤트당 한 행(수신자, 블록, 동작, 값, 타임스탬프)을 제공합니다.
설문조사 생명주기
프로젝트에는 마감일과/또는 응답 상한(maxResponses)을 설정할 수 있습니다. 둘 중 하나에 도달하면 새 인터랙션 이벤트는 거부됩니다 — 라이브 뷰는 인터랙티브 블록 대신 마감 안내를 보여주지만 정적 콘텐츠는 계속 표시됩니다 — 그리고 응답 페이지는 설문조사가 현재 마감되었는지를 보여줍니다. 소급 필터링은 없습니다: 이미 기록된 응답은 데이터에 그대로 남습니다.
인앱 저점수 알림
아래의 웹훅 lowScore 플래그와 별개로, 프로젝트는 Zapier/Make 단계 없이 직접 알릴 이메일 주소를 몇 개까지 지정할 수 있습니다. 평점 응답이 블록에 설정된 임계값을 넘을 때마다 MailInApp은 여러분 자신의 SMTP 설정을 통해 해당 주소로 질문, 점수, 알려진 경우 수신자의 신원, 그리고 응답 페이지로 바로 연결되는 링크를 담아 이메일을 보냅니다. SMTP 릴레이가 설정되어 있지 않으면 알림은 조용히 건너뛰어지지만, 웹훅은 여전히 발동합니다. 알림은 프로젝트당 시간당으로 제한되어 저점수 폭주가 릴레이를 넘치게 하지 않도록 합니다.
집계 재구성
집계, 퍼널, 추이는 이벤트가 도착할 때마다 갱신되는 프로젝트별 미리 계산된 집계에서 제공됩니다 — 그래서 프로젝트의 기록이 아무리 많아도 빠르게 유지됩니다. 프로젝트가 예상보다 낮거나 0인 총계를 보여준다면, 이 집계가 만들어지기 전에 응답을 수집했을 가능성이 높습니다 — 응답 페이지에서 집계 재구성을 한 번 클릭하면 전체 이벤트 기록을 다시 재생해 집계에 반영합니다. 새 프로젝트는 이 작업이 전혀 필요하지 않습니다.
웹훅
데이터가 여러분 자신의 시스템 — CRM, 스프레드시트, 자동화 도구 — 으로 들어가길 원한다면, 같은 응답 페이지에서 웹훅을 설정하세요: HTTPS URL을 입력하고 활성화를 클릭합니다.
두 가지 일이 일어납니다:
- 서명 시크릿(
whsec_…)이 표시됩니다 — 즉시 복사하세요, 오직 이번 한 번만 표시됩니다. 이는 서버 측에 저장되며 이후로는 MailInApp의 다른 모든 자격 증명과 마찬가지로 어디서나 마스킹됩니다. - 이후로는 모든 인터랙션이 기록되는 즉시 JSON으로 여러분의 URL에 POST됩니다.
시크릿을 회전(새 시크릿이 발급되어 한 번 표시됩니다)하거나 언제든 웹훅을 제거할 수 있습니다.
페이로드
{
"type": "interaction.received",
"projectId": "abc123",
"event": {
"campaignId": "abc123",
"blockId": "poll-1",
"blockType": "poll",
"action": "vote",
"value": { "option": "Blue" },
"recipient": "row:3",
"projectId": "abc123",
"receivedAt": 1752480000000
},
"recipient": {
"key": "row:3",
"row": { "email": "[email protected]", "first_name": "Ada" }
},
"lowScore": false
}
event.value는 수집된 데이터 자체입니다 — 선택된 투표 옵션, 폼의 필드 값, 별점 개수입니다.- 익명 인터랙션의 경우
recipient는null입니다. 귀속된 인터랙션의 경우key는 데이터 소스에서 수신자의 행 인덱스입니다("row:3"= 네 번째 행). recipient.row— 수신자의 전체 데이터 행 — 은 호스팅된 데이터 소스에만 포함됩니다. API 타입 소스의 경우 모든 인터랙션마다 여러분의 엔드포인트를 호출하지 않으므로, 여러분 쪽에서 행 인덱스로 조인해야 합니다.lowScore는 이벤트가 평점 블록의rate동작이고 그 값이 해당 블록에 설정된 알림 임계값 이하일 때true입니다 — Zapier/Make 자동화(또는 여러분 자신의 인앱 알림)가 지원 담당자를 호출하기 위해 필터링하는 신호입니다. 평점이 아닌 이벤트이거나 블록에 임계값이 설정되지 않은 경우에는 완전히 생략됩니다.
서명 검증
모든 전달은 여러분의 엔드포인트가 실제로 MailInApp에서 온 것임을 확인할 수 있도록 서명됩니다. 두 개의 헤더가 전송됩니다:
| 헤더 | 내용 |
| --- | --- |
| X-MailInApp-Timestamp | 전달이 서명된 시각, 에포크 밀리초 단위 |
| X-MailInApp-Signature | v1= 다음에 16진수 HMAC-SHA256(secret, timestamp + "." + rawBody)가 이어짐 |
원시 요청 본문(JSON 파싱 이전)으로부터 예상 서명을 계산하고 상수 시간 비교로 대조하세요. 오래된 타임스탬프를 거부하면 재전송된 전달을 차단할 수 있습니다:
import { createHmac, timingSafeEqual } from "node:crypto";
function isValidDelivery(headers, rawBody, secret) {
const timestamp = headers["x-mailinapp-timestamp"];
const given = Buffer.from(headers["x-mailinapp-signature"] ?? "");
const expected = Buffer.from(
"v1=" +
createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex"),
);
if (given.length !== expected.length || !timingSafeEqual(given, expected)) {
return false;
}
// Reject deliveries signed more than 5 minutes ago (replay protection).
return Math.abs(Date.now() - Number(timestamp)) < 5 * 60 * 1000;
}
전달 방식
- 첫 시도는 즉시, 이후 자동으로 재시도됩니다. 전달은 5초 후 타임아웃됩니다.
2xx응답에 못 미치는 모든 것(타임아웃, 연결 실패, 오류 상태)은 실패로 처리됩니다. 이벤트는 항상 먼저 MailInApp에 저장되므로, 전달을 놓쳐도 아무것도 잃지 않습니다 — 웹훅은 실시간 신호로, 응답 화면은 진실 공급원으로 취급하세요. - 백오프를 적용한 자동 재시도. 실패한 전달은 점점 늘어나는 간격 — 대략 1분, 5분, 30분, 2시간, 그다음 6시간 — 으로 웹훅의 현재 URL과 시크릿을 대상으로 재시도되므로, 회전된 시크릿이나 변경된 URL도 자동으로 반영됩니다. 모든 재시도가 계속 실패하면 전달은 더 이상 스스로 재시도하지 않지만, 절대 폐기되지는 않습니다.
- 수동 재전달. 여전히 실패 중인(재시도 중이거나 소진된) 전달은 응답 페이지의 실패한 전달 아래에 마지막 실패 사유와 재전달 버튼과 함께 표시됩니다 — 여러분 쪽에서 문제를 고친 직후, 다음 예약된 재시도를 기다리지 않고 바로 사용하면 유용합니다.
- 수신자를 절대 방해하지 않습니다. 전달은 수신자의 인터랙션이 확인된 뒤에 이루어지므로, 느리거나 고장 난 엔드포인트가 투표나 제출을 지연시키거나 실패하게 만들 수 없습니다.
- 빠르게 응답하세요. 어떤
2xx든 빠르게 반환하고 무거운 처리는 비동기로 하세요.
신뢰에 대한 참고: 인터랙션 엔드포인트는 필연적으로 공개되어 있으므로(받은편지함은 인증할 수 없습니다) 익명 이벤트는 설계상 인증되지 않습니다. 귀속된 이벤트는 서명된 수신자 토큰으로 보호됩니다. 전달 서명을 검증하고,
event.value를 사용자 입력으로 취급하세요.