Skip to content

Worked example: transactional email (Korean fintech)

Generated by skills/document-author (with email subtype) or by direct application of knowledge/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:    결제 완료 — 주문번호 #1234
Preheader:  스타벅스 강남점 ₩9,000 · 카카오페이로 결제됨

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:0018: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)

Subject:    결제 실패 — 주문번호 #1234
Preheader:  결제 처리 중 오류가 발생했습니다. 다시 시도해 주세요.

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

Subject:    환불 완료 — 주문번호 #1234

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