Worked example: transactional email (Korean fintech)¶
Generated by
skills/document-author(with email subtype) or by direct application ofknowledge/patterns/email-design.md. Demonstrates a Korean transactional email with all the required elements: preheader, bulletproof button, sender info per Korean spam law, receipt-style breakdown.
Context¶
A Korean 가계부 / fintech app sends a "결제 완료" email after each transaction. Required: - Korean ~합니다 voice (formal — fintech) - Order detail prominent - Single primary CTA - Sender info per 정보통신망법 - Mobile + desktop responsive - Tested in Apple Mail, Gmail, Outlook, Naver Mail, Daum Hanmail
Subject + preheader¶
Subject under 50 chars. Preheader specific (amount + merchant).
Email body (rendered React Email / MJML output)¶
import { EmailLayout, Heading, Paragraph, Button, Section, Hr, Img } from "@/email";
export function PaymentReceiptEmail({ user, order }: Props) {
return (
<EmailLayout
preheader={`${order.merchant} ${formatKRW(order.total)} · ${order.paymentMethodLabel}로 결제됨`}
lang="ko"
brandColor="#0D9488"
>
<EmailLayout.Header>
<Img src="https://example.com/logo.png" alt="우리 가계부" width="120" height="40" />
</EmailLayout.Header>
<EmailLayout.Body>
<Heading style={{ fontSize: 24, fontWeight: 700, marginBottom: 8 }}>
결제가 완료되었습니다
</Heading>
<Paragraph style={{ color: "#475569", fontSize: 14, marginBottom: 24 }}>
{formatKRDate(order.completedAt, "long")}
</Paragraph>
<Paragraph>
{user.name} 님, 안녕하세요.
</Paragraph>
<Paragraph>
<strong>{order.merchant}</strong>에서 {formatKRW(order.total)} 결제가
정상적으로 처리되었습니다.
</Paragraph>
{/* Receipt-style summary box */}
<Section style={{
background: "#F8FAFC",
padding: 20,
borderRadius: 8,
marginTop: 24,
}}>
<Heading as="h2" style={{ fontSize: 16, fontWeight: 600, marginBottom: 12 }}>
주문 정보
</Heading>
<Hr style={{ borderColor: "#E2E8F0", borderStyle: "dashed", margin: "12px 0" }} />
<table role="presentation" cellPadding="0" cellSpacing="0" style={{ width: "100%" }}>
<tbody>
<tr><td style={{ color: "#64748B", padding: "4px 0" }}>주문번호</td>
<td style={{ textAlign: "right", padding: "4px 0", fontFamily: "monospace" }}>
#{order.id}
</td></tr>
<tr><td style={{ color: "#64748B", padding: "4px 0" }}>결제 수단</td>
<td style={{ textAlign: "right", padding: "4px 0" }}>
{order.paymentMethodLabel}
</td></tr>
<tr><td style={{ color: "#64748B", padding: "4px 0" }}>결제 시각</td>
<td style={{ textAlign: "right", padding: "4px 0" }}>
{formatKRTime(order.completedAt)}
</td></tr>
</tbody>
</table>
<Hr style={{ borderColor: "#E2E8F0", borderStyle: "dashed", margin: "16px 0" }} />
{/* Items */}
{order.items.map(item => (
<table key={item.id} role="presentation" style={{ width: "100%", marginBottom: 8 }}>
<tr>
<td style={{ padding: "4px 0" }}>
{item.name}
{item.quantity > 1 && <span style={{ color: "#64748B" }}> × {item.quantity}</span>}
</td>
<td style={{ textAlign: "right", padding: "4px 0", fontFeatureSettings: "'tnum'" }}>
{formatKRW(item.totalPrice)}
</td>
</tr>
</table>
))}
<Hr style={{ borderColor: "#E2E8F0", borderStyle: "dashed", margin: "16px 0" }} />
{/* Total */}
<table role="presentation" style={{ width: "100%" }}>
<tr>
<td style={{ fontWeight: 700, padding: "8px 0" }}>총 결제 금액</td>
<td style={{
textAlign: "right",
fontWeight: 700,
fontSize: 18,
fontFeatureSettings: "'tnum'",
padding: "8px 0",
}}>
{formatKRW(order.total)}
</td>
</tr>
</table>
</Section>
{/* Primary CTA — bulletproof button */}
<table role="presentation" cellPadding="0" cellSpacing="0" style={{ marginTop: 32 }}>
<tr>
<td bgcolor="#0D9488" style={{ borderRadius: 8 }}>
<a href={`https://example.com/orders/${order.id}`}
style={{
display: "inline-block",
padding: "14px 32px",
color: "#FFFFFF",
textDecoration: "none",
fontFamily: "Pretendard, -apple-system, sans-serif",
fontSize: 16,
fontWeight: 600,
borderRadius: 8,
}}>
주문 상세 보기
</a>
</td>
</tr>
</table>
<Paragraph style={{ color: "#64748B", fontSize: 14, marginTop: 32 }}>
본인이 결제하지 않으셨다면 즉시{" "}
<a href="https://example.com/support" style={{ color: "#0D9488" }}>
고객센터
</a>
로 문의해 주세요.
</Paragraph>
</EmailLayout.Body>
<EmailLayout.Footer>
<Paragraph style={{ fontSize: 12, color: "#94A3B8", lineHeight: 1.6 }}>
(주)우리가계부 · 대표 김민지 · 사업자등록번호 123-45-67890<br />
서울특별시 강남구 테헤란로 123, 5층<br />
문의: <a href="mailto:support@example.com" style={{ color: "#94A3B8" }}>support@example.com</a>
{" · "}
전화 02-1234-5678 (평일 09:00–18:00)
</Paragraph>
<Paragraph style={{ fontSize: 12, color: "#94A3B8", marginTop: 12 }}>
본 메일은 결제 완료 안내를 위한 발송 메일입니다. 광고가 아닙니다.
</Paragraph>
</EmailLayout.Footer>
</EmailLayout>
);
}
What this demonstrates¶
- Subject + preheader pair: subject is action-specific, preheader fills inbox preview with detail.
- Greeting: 사용자 이름 + 안녕하세요 (Korean polite opener).
- Receipt structure: dashed dividers between sections (Korean receipt convention — see
examples/component-payment-receipt.md). - Tabular numerals on amounts (
fontFeatureSettings: 'tnum'). - Bulletproof button for "주문 상세 보기" — works in Outlook desktop.
- Single primary CTA — no marketing tacked on.
- Help text below CTA — fraud-detection path ("본인이 결제하지 않으셨다면").
- Footer with sender info per 정보통신망법: company, representative, business registration, address, contact.
- Explicit "광고가 아닙니다" — distinguishes from marketing emails (which require
[광고]prefix in subject).
Sender + identity guarantees¶
For DKIM / SPF / DMARC:
- Send from noreply@example.com (different from contact support@).
- Reply-To set to support@example.com (real address).
- DMARC policy p=quarantine minimum.
- For Korean delivery to Naver / Daum: register sender domain with KISA (Korea Internet & Security Agency) for whitelist treatment.
Mobile rendering¶
The EmailLayout wrapper applies the @media (max-width: 480px) rules:
- Container goes full-width.
- Padding reduces 24px → 16px.
- Receipt table cells stay legible.
Test matrix¶
Before shipping any new transactional template, render through:
| Client | Expected behavior |
|---|---|
| Gmail (web) | Renders cleanly with brand color |
| Gmail iOS | Renders cleanly |
| Apple Mail (Mac) | Renders cleanly; "Hide image" doesn't break content |
| Apple Mail (iOS 17+) | Renders cleanly; loads images without privacy alert |
| Outlook desktop (Windows) | Bulletproof button works; no broken layout |
| Outlook web | Renders cleanly |
| Naver Mail | Renders cleanly with Korean characters |
| Daum Hanmail | Renders cleanly with Korean characters |
Use Litmus or Email on Acid for parallel client previews.
Common variations¶
Order failed (transactional, but bad outcome)¶
Body:
- Status header in --color-warning color (not error-red — failed-payment is recoverable).
- "왜 실패했는지" explanation (insufficient funds / declined / timeout).
- "다시 시도하기" CTA.
- Help text + 1:1 inquiry link.
Refund completed¶
Body: - Status header. - Refund amount + original order link. - Bank info / KakaoPay account where refund was sent. - Expected arrival time ("영업일 1–3일").
Why this is a good transactional email example¶
- One purpose: confirms payment. No marketing.
- Subject specific: "주문번호 #1234" not "주문 안내".
- Preheader fills the preview: amount + merchant + payment method in one line.
- Body leads with the answer: "결제가 완료되었습니다".
- Receipt section is scannable: dashed dividers, tabular numerals, total bolder.
- One CTA, bulletproof button.
- Sender info per 정보통신망법: required by Korean law.
- Self-distinguishes from marketing: "본 메일은 ... 광고가 아닙니다."
- Polite tone (~합니다) — fintech context.
Cite knowledge/patterns/email-design.md and knowledge/i18n/korean-document-style.md.
Cross-reference¶
knowledge/patterns/email-design.md— broader email rulesexamples/component-email-layout.md— email scaffoldingexamples/component-payment-receipt.md— in-app receipt patternknowledge/i18n/korean-payments.md— payment contextknowledge/i18n/korean-document-style.md— voice