상품 블록
지금 구매 버튼이 있는 상품 카드입니다. 체크아웃 필드가 탭했을 때 실제로 어디로 이동할지를 결정합니다. **MailInApp 체크아웃(Stripe)**은 실제 결제 흐름을 그대로 포함합니다 — 별도의 스토어프론트도, 만들어야 할 체크아웃 페이지도 필요 없고, 카드 정보가 MailInApp 자체 서버에 닿는 일도 전혀 없습니다. 외부 스토어 체크아웃으로 연결은 대신 구매자를 여러분이 직접 운영하는 Shopify/WooCommerce 스토어의 상품 페이지로 곧장 보냅니다 — 판매(그리고 그에 딸린 재고, 세금, 할인)를 이미 운영 중인 스토어 쪽에 그대로 남겨두고 싶을 때 사용합니다.
MailInApp 체크아웃(Stripe)
이 블록의 기본 모드이며, 이 섹션의 내용은 모두 이 모드에만 해당합니다 — 다른 모드는 아래 대신 자신의 스토어 체크아웃으로 연결하기를 참고하세요. 먼저 설정 → 결제에서 자신의 Stripe 계정을 연결하세요(Stripe Connect, Standard/OAuth). 모든 결제 금액은 그 계정으로 직접 정산됩니다.
투표나 평점과 달리 구매는 Stripe 자체의 호스팅된 체크아웃 페이지에서만 안전하게 완료될 수 있으므로, 이 블록에는 이메일 내 키네틱 티어가 전혀 없습니다. 지금 구매는 메일을 포함한 모든 곳에서 항상 링크 우선으로 동작합니다. 탭하면 항상 호스팅된 라이브 뷰의 확인 페이지(/v/[token]/act?blockId=...&blockType=product&action=buy)가 먼저 열리고, 이 페이지는 상품명과 가격을 다시 보여준 뒤 실제로 무언가를 생성하기 전에 한 번 더 탭("결제 계속하기")을 요구합니다.
이 "확인 후 POST" 구조는 의도적인 설계입니다: 이메일의 모든 링크를 미리 가져오는 보안 스캐너나 기업 프록시가 단순 GET만으로 실제 Stripe Checkout Session을 발생시켜서는 절대 안 되기 때문입니다. 확인 페이지에서의 명시적인 POST만이 POST /api/checkout에 도달합니다. 이 라우트는 가격, 이름, 재고를 클라이언트가 보낸 값이 아니라 항상 블록 자체에 서버 측으로 저장된 설정에서 확인합니다. 그런 다음 소유자가 연결한 Stripe 계정에 Checkout Session을 생성하고, pending 상태의 주문을 기록한 뒤 303으로 Stripe로 리디렉션합니다.
pending 상태의 주문은 아직 판매로 집계되지 않습니다. 주문을 paid로 전환하는 것은 오직 POST /api/webhooks/stripe뿐입니다. 이는 Stripe 자체의 서명으로 인증되며, 카운트다운 및 열람 추적 엔드포인트의 HMAC URL과 동일한 신뢰 모델을 사용합니다 — 구매자의 브라우저가 도착하는 성공 URL 리디렉션은 어디까지나 UX일 뿐, 결제 증명으로 신뢰할 수 없기 때문입니다.
이 웹훅에서 MailInApp은 확정 전에 트랜잭션 단위로 재고를 다시 확인합니다. 두 구매자가 마지막 한 개를 두고 경쟁하다 둘 다 Stripe를 통과했다면, 진 쪽의 결제는 자동으로 환불되고 안내 메일이 발송됩니다 — 상품이 조용히 초과 판매되는 대신입니다. 결제가 확정되면 purchase 인터랙션 이벤트도 함께 기록되므로, 수익은 다른 모든 블록의 응답과 동일한 집계 및 프로젝트 웹훅 파이프라인을 그대로 거쳐 흐릅니다. 인터랙션 & 분석을 참고하세요.
풀필먼트는 풀필먼트 필드에 따라 달라집니다:
- 디지털 — 배송할 콘텐츠(다운로드 링크나 코드)를 블록에 직접 입력합니다. 웹훅이 결제를 확인하는 즉시 해당 콘텐츠가 구매자에게 자동으로 이메일 발송됩니다.
- 물리 — Stripe Checkout이 결제 흐름의 일부로 배송지 주소를 수집합니다. 주문은 풀필먼트 완료로 표시를 클릭할 때까지 프로젝트의 주문 테이블에 남아 있으며, 클릭하면 구매자에게 발송 안내 메일이 전송됩니다.
재고는 선택적인 상한입니다(0 = 무제한). 발송되는 HTML은 발송 시점에 정적으로 고정된다는, 카운트다운 블록의 마감일이나 미팅 링크 블록의 참가 가능 시간대와 같은 규칙을 따르므로, 상한이 있는 상품이라도 재고 수량이 텍스트로 그대로 박히지는 않습니다. 대신 이메일에는 열람할 때마다 다시 생성되는 작은 서버 렌더링 재고 알약형 이미지("3개 남음" / "품절")가 삽입되어, 발송 며칠 뒤에도 오래된 재고 정보가 표시되는 일이 없습니다. 호스팅된 라이브 뷰에서는 재고가 실시간으로, 동적으로 확인됩니다: 결제 완료된 주문이 상한에 도달하면 지금 구매는 클릭 가능한 버튼 옆에 배지만 추가되는 것이 아니라, 비활성화된 "품절" 컨트롤로 완전히 대체됩니다. 어느 경우든 실제 근거는 결제 시점에 웹훅이 수행하는 트랜잭션 재확인이며, 배지와 비활성화된 버튼은 강제 메커니즘이 아니라 단순한 UX 편의입니다.
Shopify나 WooCommerce 스토어를 연결했다면, 이 필드들 위에 스토어에서 가져오기 검색창이 나타나 해당 스토어 카탈로그의 상품을 나열합니다. 별도로 눌러야 할 버튼 없이 백그라운드에서 자동으로 동기화 상태를 유지합니다. 상품을 선택하면 이름, 설명, 이미지, 가격이 자동으로 채워집니다.
동기화된 상품에 알려진 스토어프론트 페이지(Shopify 자체의 상품 핸들, 또는 WooCommerce의 페이지 URL)가 있다면, 가져오기와 동시에 체크아웃도 외부 스토어 체크아웃으로 연결로 전환되고 해당 페이지가 외부 상품 페이지 URL로 채워집니다. 이렇게 가져온 상품은 더 이상 설정할 것 없이 바로 자신의 스토어에서 판매할 준비가 됩니다. 스토어 연결이 페이지 URL을 지원하기 전에 동기화된 상품은 대신 MailInApp 체크아웃에 그대로 남으며, 내부적으로 아무것도 바뀌지 않습니다.
이는 일회성 복사이며, 실시간으로 연동되는 링크가 아닙니다. 이후 모든 필드는 자유롭게 수정할 수 있고, 체크아웃 시 실제로 청구되는 가격은 항상 블록이 현재 보유한 값이며 스토어에서 다시 가져오는 일은 없습니다. 아래 필드들은 스토어 연결 여부와 관계없이 동일하게 동작합니다 — 가져오기는 지름길일 뿐 필수는 아닙니다.
대신 자신의 스토어 체크아웃으로 연결하기
체크아웃을 외부 스토어 체크아웃으로 연결로 전환하고 외부 상품 페이지 URL을 설정하면 — 여러분의 Shopify 상품 페이지, 장바구니 퍼머링크, WooCommerce 상품 페이지, 또는 임의의 https:// 링크 등 — MailInApp 자체의 결제 흐름을 완전히 건너뜁니다. 이때 지금 구매는 일반 링크가 걸린 버튼이나 이미지와 완전히 동일하게 동작합니다: 확인 페이지도, /api/checkout도, Stripe도 없습니다. 클릭 자체는 여전히 추적되므로(클릭 히트맵에 반영됩니다), 구매자는 곧바로 여러분의 스토어에 도착해 그곳에서 구매를 완료합니다.
MailInApp은 이 결제 과정에 전혀 관여하지 않으므로, 위에서 설명한 MailInApp 체크아웃 관련 메커니즘은 외부 상품에는 하나도 적용되지 않습니다. pending/paid 주문도, 주문 테이블 항목도, 풀필먼트나 환불 액션도, 재고 강제나 재고 상태 배지도, 구매로 촉발되는 여정 단계도 없습니다. 해당 수익은 자신의 스토어에서 발생한 다른 판매와 동일한 방식으로 추적하세요. 스토어 측 구매를 그 계기가 된 이메일에 귀속시키는 방법은 Shopify 주문 & 체크아웃 수익 추적에서 다룹니다.
체크아웃이 외부로 설정된 상태에서 외부 상품 페이지 URL이 비어 있거나 유효한 https:// 링크가 아니라면, 블록은 작동하지 않는 버튼을 표시하는 대신 조용히 MailInApp 체크아웃 모드와 완전히 동일하게 동작하는 방식으로 되돌아갑니다.
상품별 할인
블록이 스토어에서 가져오기를 통해 채워져(직접 입력한 URL이 아니라 실제 storeProductId를 가지고 있는 상태) 체크아웃이 외부로 설정되면 상품별 할인 토글이 나타납니다. 이를 켜고 할인 유형(퍼센트 또는 정액), 할인 값, **만료(발송 후 일수)**를 설정하세요. 스튜디오 캔버스는 즉시 다시 그려져 수신자가 실제로 보게 될 것과 동일한 할인 배지와 취소선이 그어진 가격을 보여주므로, 확인을 위해 라이브 뷰를 열 필요가 없습니다. 각 수신자의 이메일이 렌더링되기 직전, MailInApp은 연결된 Shopify 또는 WooCommerce 스토어에 일회용 할인 코드를 발급합니다 — 이 코드는 스토어 전체가 아니라 해당 수신자와 이 상품에만 제한됩니다 — 그리고 지금 구매를 코드가 이미 적용된 상태로 쇼핑객을 이 상품 페이지로 돌려보내는 교환 링크로 다시 씁니다. 이는 발송 페이지의 프로젝트 수준 할인 오퍼(할인 오퍼 참고)와는 독립적입니다: 프로젝트는 둘 중 하나, 둘 다, 또는 둘 다 사용하지 않을 수 있으며, 각각 자체 쿨다운을 유지하므로 한쪽이 다른 쪽을 막는 일이 없습니다. 연결된 스토어에서 가져오지 않은 상품을 가진 블록에는 대신 토글이 숨겨진 이유를 설명하는 안내가 표시됩니다. 처음부터 끝까지 다루는 내용은 Shopify 상품 할인 코드와 WooCommerce 상품 할인 코드를 참고하세요.
Shopify 스토어의 경우, 체크아웃 전에 실제 상품 페이지 자체에도 이 동일한 배지를 표시할 수 있는 선택적 앱 블록이 있습니다 — 설정 방법은 상품 페이지에 할인 표시하기(Shopify)를 참고하세요.
특정 수신자에 대해 코드 발급이 실패하더라도(일치하는 스토어 고객이 없거나, 토큰 재연결이 필요하거나, 실시간 API에 일시적 문제가 있는 경우 등) 해당 수신자의 이메일은 그대로 발송됩니다 — 지금 구매는 그저 블록의 평범한, 할인 없는 상품 링크로 되돌아갈 뿐입니다.
설정 가능한 필드:
- 이름, 설명, 이미지 — URL로 직접 입력하는 대신 미디어 라이브러리에서 선택하거나, 위의 스토어에서 가져오기로 자동 입력됩니다.
- 가격과 통화(USD, EUR, GBP) — 어느 모드에서든 카드에 표시되며, 외부 모드에서는 정보 제공 목적일 뿐입니다.
- 체크아웃 — MailInApp 체크아웃(Stripe) 또는 외부 스토어 체크아웃으로 연결.
- 외부 상품 페이지 URL — 외부 모드에서만 사용되며, 지금 구매가 구매자를 보내는 곳입니다.
- 상품별 할인, 할인 유형, 할인 값, 만료(발송 후 일수) — 외부 모드에서만, 그리고 블록의 상품이 스토어에서 가져오기로 채워진 경우에만 사용됩니다.
- 풀필먼트 — 디지털 또는 물리; MailInApp 체크아웃 모드에서만 사용됩니다.
- 재고 — 0이면 무제한; MailInApp 체크아웃 모드에서만 사용됩니다.
- 전달 콘텐츠 — 디지털 전용; 결제 후 전송되는 다운로드 링크나 코드입니다; MailInApp 체크아웃 모드에서만 사용됩니다.
- 배경색, 패딩, 테두리, 모서리 반경, 그리고 이름과 설명에 대한 텍스트 스타일 재정의.
예시
Subject
Back in stock: the Weekender Tote
굿즈 드롭이나 한정판 인쇄물처럼 정확히 맞아떨어지는 사례입니다: 재고를 생산 수량만큼 상한으로 설정하고, 재고 알약형 이미지가 소진되는 만큼 희소성을 전달하도록 하세요. 클릭을 별도 스토어로 우회시키는 대신 프로모션 발송에서 곧바로 판매하는 더 넓은 패턴은 이커머스 & 상품 드롭을 참고하세요. 디지털 강좌나 전자책 출시에는 디지털 풀필먼트를 사용해, 결제가 완료되는 즉시 구매자가 다운로드 링크를 받도록 하고 수동 풀필먼트 단계를 없앨 수 있습니다. 실물 부가 상품(브랜드 굿즈, 시즌 한정 박스 등)을 판매하는 지역 비즈니스는 물리 풀필먼트를 사용해 주문 테이블을 가벼운 주문 대기열처럼 운용하며, 발송할 때마다 완료로 표시합니다. 주소 확인이 필요하다면 구매자에게 문의를 사용해 지원 티켓을 여세요.
정적 폴백의 모습
<div style="margin:12px 0;padding:16px;border:1px solid #e5e7eb;
border-radius:8px;background-color:#ffffff">
<p style="margin:0 0 4px;font-weight:600;font-size:16px;color:#111827">
Limited edition tote bag
</p>
<p style="margin:0 0 10px;font-weight:700;font-size:18px">$29.00</p>
<img src="https://mailinapp.com/api/product-status?p=proj123&b=prod-1&s=..."
width="180" height="30" alt="" style="display:block;margin-bottom:8px" />
<a href="https://mailinapp.com/v/eyJhbGci.../act?blockId=prod-1&blockType=product&action=buy"
style="display:inline-block;padding:10px 20px;background-color:#4f46e5;
color:#ffffff;border-radius:6px;text-decoration:none;
font-size:14px;font-weight:600">
Buy now
</a>
</div>
재고 상태 이미지는 재고 상한이 설정된 경우에만 렌더링됩니다. 지금 구매는 이메일 내부에서 직접 결제를 POST하는 대신 항상 확인 페이지를 엽니다.
외부 체크아웃 모드에서는 확인 페이지도 재고 배지도 전혀 없습니다 — 지금 구매는 외부 상품 페이지 URL로 곧장 향하는, 클릭만 추적되는 평범한 링크입니다:
<div style="margin:12px 0;padding:16px;border:1px solid #e5e7eb;
border-radius:8px;background-color:#ffffff">
<p style="margin:0 0 4px;font-weight:600;font-size:16px;color:#111827">
Limited edition tote bag
</p>
<p style="margin:0 0 10px;font-weight:700;font-size:18px">$29.00</p>
<a href="https://mailinapp.com/v/eyJhbGci.../click?blockId=prod-1&blockType=product&dest=https%3A%2F%2Fshop.example.com%2Fproducts%2Ftote-bag"
style="display:inline-block;border:none;border-radius:6px;
background-color:#4f46e5;color:#ffffff;padding:10px 20px;
font-size:14px;font-weight:600;text-decoration:none">
Buy now
</a>
</div>
관련 페이지
- 블록 리퍼런스 개요
- 주문, 풀필먼트, 환불
- 지원 티켓
- 인터랙션 & 분석
- Shopify / WooCommerce — 스토어를 연결하면 스토어에서 가져오기 피커를 사용할 수 있습니다
- Shopify 주문 & 체크아웃 수익 추적 — 자신의 스토어 체크아웃에서 이루어진 구매를 그 계기가 된 이메일에 귀속시키기
- Shopify 상품 할인 코드 / WooCommerce 상품 할인 코드 — 이 블록에서 직접 상품별 할인을 발급하기