Files
fe-agent/.claude/rules/markup/email-html-table.md
hyeonggil 5fe888c88f 📝 docs: Update CLAUDE.md and add frontend coding conventions
- Expanded CLAUDE.md with behavioral guidelines for LLM coding practices.
- Introduced new documents for frontend code style, Nuxt conventions, and testing conventions.
- Added detailed rules for email HTML structure and TailwindCSS styling strategy.
- Included a comprehensive EDM email HTML implementation guide.
2026-04-07 23:20:02 +09:00

21 KiB

paths
paths
**/*.html

이메일 발송용 HTML Table 코딩 Rules

Gmail, Naver Mail, Outlook 등 주요 이메일 클라이언트 호환 기준 최종 업데이트: 2026-04-07


왜 이메일 HTML은 특별한가?

이메일 클라이언트는 웹 브라우저와 다르게 동작한다.

클라이언트 렌더링 엔진 주요 제한
Gmail (웹) WebKit 기반 <head> 스타일 일부 제거, <style> 지원 제한적
Gmail (앱) Gmail 자체 파서 외부 CSS 불가, 인라인 스타일 필수
Outlook 2016~2021 Microsoft Word (MSHTML) Flexbox/Grid 미지원, CSS 한계
Outlook 365 (웹) WebKit 비교적 현대적
Naver Mail (웹) WebKit 기반 <style> 범위 제한
Apple Mail WebKit 현대 CSS 대부분 지원
Samsung Mail WebKit 기반 대부분 지원

결론: 가장 제한적인 Outlook + Gmail 앱을 기준으로 코딩해야 한다.


빠른 참조 체크리스트

코드 작성 전/리뷰 시 아래 항목을 확인한다.

  • 레이아웃에 <table> 구조를 사용했는가? (Flexbox/Grid 금지)
  • 모든 스타일이 인라인(style="")으로 작성되었는가?
  • <table>role="presentation" 속성이 있는가?
  • <table>border="0" cellpadding="0" cellspacing="0"이 설정되어 있는가?
  • 너비를 width 속성과 style="width:"동시에 명시했는가?
  • 모든 색상이 6자리 HEX(#ffffff)로 표기되어 있는가? (3자리, rgb(), rgba() 금지)
  • 폰트에 웹 안전 폰트(fallback 포함)를 사용했는가?
  • 이미지에 alt, width, height, border="0", display:block이 모두 있는가?
  • 전체 컨테이너 너비가 600px 이하인가?
  • <html>, <head>, <body> 태그를 모두 포함했는가?
  • <meta charset="UTF-8">과 viewport 메타 태그가 있는가?
  • MSO 조건부 주석(<!--[if mso]>)으로 Outlook 버튼을 대응했는가?
  • 배경 이미지 대신 배경색(bgcolor)을 주요 배경으로 사용했는가?
  • <td>line-height를 명시했는가? (Outlook 기본값 불일치)

규칙 상세

Rule 1: 기본 HTML 골격

모든 이메일 HTML은 아래 골격을 기반으로 시작한다.

DO: 표준 이메일 골격

<!DOCTYPE html>
<html lang="ko" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="x-apple-disable-message-reformatting" />
  <title>이메일 제목</title>
  <!--[if mso]>
  <noscript>
    <xml>
      <o:OfficeDocumentSettings>
        <o:PixelsPerInch>96</o:PixelsPerInch>
      </o:OfficeDocumentSettings>
    </xml>
  </noscript>
  <![endif]-->
  <style>
    /* 리셋 스타일: <head>에서만 전역 리셋 허용 */
    * { box-sizing: border-box; }
    body { margin: 0; padding: 0; width: 100% !important; }
    img { -ms-interpolation-mode: bicubic; }
    a { text-decoration: none; }

    /* 모바일 반응형 */
    @media only screen and (max-width: 600px) {
      .email-container { width: 100% !important; }
      .stack-on-mobile { display: block !important; width: 100% !important; }
      .hide-on-mobile { display: none !important; }
      .show-on-mobile { display: block !important; }
      .full-width-image img { width: 100% !important; height: auto !important; }
    }
  </style>
</head>
<body style="margin: 0; padding: 0; background-color: #f4f4f4; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%;">
  <!-- 이메일 미리보기 텍스트 (받은편지함 목록에서 표시) -->
  <div style="display: none; max-height: 0; overflow: hidden; mso-hide: all;">
    미리보기 텍스트가 여기에 표시됩니다.&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;
  </div>

  <!-- 이메일 전체 래퍼 테이블 -->
  <table
    role="presentation"
    border="0"
    cellpadding="0"
    cellspacing="0"
    width="100%"
    style="background-color: #f4f4f4;"
  >
    <tr>
      <td align="center" style="padding: 20px 10px;">

        <!-- 이메일 본문 컨테이너 (최대 600px) -->
        <table
          class="email-container"
          role="presentation"
          border="0"
          cellpadding="0"
          cellspacing="0"
          width="600"
          style="max-width: 600px; width: 600px; background-color: #ffffff;"
        >
          <tr>
            <td>
              <!-- 섹션별 콘텐츠 삽입 -->
            </td>
          </tr>
        </table>

      </td>
    </tr>
  </table>
</body>
</html>

DON'T: 불완전한 골격

<!-- 금지: DOCTYPE, head 없이 body 내용만 작성 -->
<table>
  <tr>
    <td>내용</td>
  </tr>
</table>

<!-- 금지: div로 레이아웃 구성 -->
<div style="max-width: 600px; margin: 0 auto;">
  <div style="display: flex;">내용</div>
</div>

Rule 2: 레이아웃 - Table 구조 필수

이메일에서는 모든 레이아웃을 <table>로 구성한다. div, Flexbox, CSS Grid는 Outlook에서 동작하지 않는다.

열 분할 패턴

DO: 2열 레이아웃 (테이블 중첩)
<!-- 2열 레이아웃: 각 열을 <td>로 분리 -->
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="600">
  <tr>
    <!-- 왼쪽 열: 280px -->
    <td
      class="stack-on-mobile"
      valign="top"
      width="280"
      style="width: 280px; padding: 16px;"
    >
      왼쪽 콘텐츠
    </td>

    <!-- 간격 열: 40px -->
    <td width="40" style="width: 40px;">&nbsp;</td>

    <!-- 오른쪽 열: 280px -->
    <td
      class="stack-on-mobile"
      valign="top"
      width="280"
      style="width: 280px; padding: 16px;"
    >
      오른쪽 콘텐츠
    </td>
  </tr>
</table>
DO: 헤더 / 본문 / 푸터 섹션 구조
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="600" style="width: 600px;">

  <!-- 헤더 섹션 -->
  <tr>
    <td align="center" bgcolor="#1a56db" style="background-color: #1a56db; padding: 24px 32px;">
      <img src="https://example.com/logo.png" alt="서비스명" width="120" height="40"
           style="display: block; width: 120px; height: 40px; border: 0;" />
    </td>
  </tr>

  <!-- 구분선 -->
  <tr>
    <td bgcolor="#e5e7eb" style="background-color: #e5e7eb; height: 1px; font-size: 0; line-height: 0;">&nbsp;</td>
  </tr>

  <!-- 본문 섹션 -->
  <tr>
    <td style="padding: 40px 32px;">
      <!-- 본문 콘텐츠 -->
    </td>
  </tr>

  <!-- 구분선 -->
  <tr>
    <td bgcolor="#e5e7eb" style="background-color: #e5e7eb; height: 1px; font-size: 0; line-height: 0;">&nbsp;</td>
  </tr>

  <!-- 푸터 섹션 -->
  <tr>
    <td align="center" bgcolor="#f9fafb" style="background-color: #f9fafb; padding: 24px 32px;">
      <!-- 푸터 콘텐츠 -->
    </td>
  </tr>

</table>
DON'T: div 또는 Flexbox 사용
<!-- 금지: Outlook에서 깨짐 -->
<div style="display: flex; gap: 20px;">
  <div style="flex: 1;">왼쪽</div>
  <div style="flex: 1;">오른쪽</div>
</div>

<!-- 금지: CSS Grid 사용 -->
<div style="display: grid; grid-template-columns: 1fr 1fr;">
  <div>왼쪽</div>
  <div>오른쪽</div>
</div>

Rule 3: 인라인 스타일 필수 (CSS 클래스 금지)

Gmail 앱과 일부 이메일 클라이언트는 <head><style> 블록을 제거한다. 모든 스타일은 인라인으로 작성한다.

<head><style>모바일 반응형(@media)과 전역 리셋에만 허용한다.

DO: 인라인 스타일 사용

<td style="
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans KR', Arial, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: #111827;
  padding: 24px 32px;
  background-color: #ffffff;
">
  안내 메시지가 여기에 들어갑니다.
</td>

DON'T: 클래스 기반 스타일

<!-- 금지: Gmail 앱에서 클래스 스타일이 제거됨 -->
<td class="content-cell">
  안내 메시지
</td>

Rule 4: 색상 표기 규칙

이메일 클라이언트 간 색상 호환을 위해 표기 방식을 통일한다.

표기법 지원 여부 사용 여부
#ffffff (6자리 HEX) 전체 클라이언트 사용
#fff (3자리 HEX) Outlook 일부 미지원 금지
rgb(255, 255, 255) Outlook 미지원 금지
rgba(255, 255, 255, 0.5) Outlook 미지원 금지
hsl(...) 대부분 미지원 금지
색상명 (red, blue) 일부만 지원 금지

DO: 6자리 HEX + bgcolor 이중 설정

<!-- bgcolor 속성(HTML 4)과 style 속성 동시 설정: 최대 호환성 -->
<td bgcolor="#1a56db" style="background-color: #1a56db;">
  내용
</td>

<table bgcolor="#f9fafb" style="background-color: #f9fafb;">
  ...
</table>

DON'T: rgba 또는 3자리 HEX 사용

<!-- 금지: Outlook에서 렌더링 안 됨 -->
<td style="background-color: rgba(26, 86, 219, 0.9);">내용</td>
<td style="color: #fff;">내용</td>

Rule 5: 폰트 및 타이포그래피

웹 안전 폰트 스택 (한국어 지원)

<!-- 한국어 지원 폰트 스택 -->
<td style="
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans KR',
               'Apple SD Gothic Neo', '맑은 고딕', Malgun Gothic, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: #111827;
">
  한국어 텍스트
</td>

타이포그래피 규칙

속성 규칙 이유
font-size px 단위 사용 em/rem 클라이언트별 기준값 상이
line-height 숫자 또는 px 모든 <td>에 명시 (Outlook 기본값 문제)
font-weight bold 또는 숫자 (700) 둘 다 명시 권장
웹 폰트 사용 금지 Gmail/Outlook 미지원, fallback만 렌더링됨

DO: 올바른 타이포그래피

<!-- 제목 -->
<h1 style="
  margin: 0 0 16px 0;
  font-family: -apple-system, 'Noto Sans KR', Arial, sans-serif;
  font-size: 24px;
  font-weight: bold;
  line-height: 1.3;
  color: #111827;
">
  이메일 제목입니다
</h1>

<!-- 본문 단락 -->
<p style="
  margin: 0 0 16px 0;
  font-family: -apple-system, 'Noto Sans KR', Arial, sans-serif;
  font-size: 15px;
  line-height: 1.7;
  color: #374151;
">
  본문 텍스트 내용입니다.
</p>

<!-- 링크 -->
<a href="https://example.com" style="color: #1a56db; text-decoration: underline;">
  링크 텍스트
</a>

DON'T: 웹 폰트, em 단위 사용

<!-- 금지: 웹 폰트 (대부분 이메일 클라이언트에서 fallback으로 치환됨) -->
<td style="font-family: 'Pretendard', sans-serif;">내용</td>

<!-- 금지: em 단위 (기준값이 클라이언트마다 다름) -->
<p style="font-size: 1em; line-height: 1.5em;">내용</p>

Rule 6: 이미지

DO: 올바른 이미지 태그

<!-- 모든 필수 속성 포함 -->
<img
  src="https://example.com/images/banner.png"
  alt="이벤트 배너: 7월 여름 세일 최대 50% 할인"
  width="600"
  height="200"
  border="0"
  style="
    display: block;
    width: 100%;
    max-width: 600px;
    height: auto;
    border: 0;
    outline: none;
    text-decoration: none;
    -ms-interpolation-mode: bicubic;
  "
/>

이미지 필수 속성 체크리스트

속성 이유
src 반드시 절대 경로(https://) 사용. 상대 경로 금지
alt 이미지 차단 시 대체 텍스트 표시
width + height 레이아웃 깨짐 방지 (HTML 속성 + style 이중 설정)
border="0" IE/Outlook에서 이미지 링크 테두리 제거
display: block 이미지 하단 여백(inline 기본값) 제거
-ms-interpolation-mode: bicubic IE/Outlook 이미지 보간 품질 향상

DON'T: 잘못된 이미지 사용

<!-- 금지: 상대 경로 사용 -->
<img src="/images/banner.png" alt="배너" />

<!-- 금지: width/height 누락 -->
<img src="https://example.com/banner.png" alt="배너" />

<!-- 금지: display:block 누락 (하단 여백 발생) -->
<img src="https://example.com/banner.png" alt="배너" width="600" height="200" />

<!-- 금지: alt 없음 (이미지 차단 시 빈 공간) -->
<img src="https://example.com/banner.png" width="600" height="200" style="display:block;" />

Rule 7: 버튼 (CTA)

Outlook은 CSS border-radius를 지원하지 않는다. 둥근 버튼은 VML(MSO 조건부 주석) 을 사용해야 한다.

DO: 크로스 클라이언트 버튼 (VML 포함)

<!-- 버튼 래퍼 td -->
<td align="center" style="padding: 24px 32px;">

  <!--[if mso]>
  <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
    href="https://example.com/cta"
    style="height:48px; v-text-anchor:middle; width:200px;"
    arcsize="10%"
    stroke="f"
    fillcolor="#1a56db">
    <w:anchorlock/>
    <center style="color:#ffffff; font-family:Arial,sans-serif; font-size:15px; font-weight:bold;">
      지금 시작하기
    </center>
  </v:roundrect>
  <![endif]-->

  <!--[if !mso]><!-->
  <a
    href="https://example.com/cta"
    style="
      display: inline-block;
      padding: 14px 32px;
      background-color: #1a56db;
      color: #ffffff;
      font-family: -apple-system, 'Noto Sans KR', Arial, sans-serif;
      font-size: 15px;
      font-weight: bold;
      line-height: 1;
      text-decoration: none;
      border-radius: 6px;
      mso-hide: all;
    "
  >
    지금 시작하기
  </a>
  <!--<![endif]-->

</td>

DON'T: 버튼 이미지 사용, CSS만으로 구현

<!-- 금지: 이미지 버튼 (이미지 차단 시 CTA 소실) -->
<td>
  <a href="https://example.com">
    <img src="https://example.com/btn.png" alt="지금 시작하기" />
  </a>
</td>

<!-- 금지: VML 없이 CSS border-radius만 사용 (Outlook에서 사각형으로 표시) -->
<a href="..." style="border-radius: 6px; background-color: #1a56db;">버튼</a>

Rule 8: 간격 조절

Outlook은 margin<td>, <table> 등에 신뢰할 수 없게 적용한다. 간격은 padding과 빈 <tr>을 활용한다.

DO: padding과 spacer tr로 간격 조절

<!-- padding으로 내부 여백 -->
<td style="padding: 24px 32px 0 32px;">
  <h2 style="margin: 0 0 16px 0; ...">제목</h2>
  <p style="margin: 0 0 16px 0; ...">본문</p>
</td>

<!-- spacer tr로 섹션 간 여백 -->
<tr>
  <td style="height: 24px; font-size: 0; line-height: 0;">&nbsp;</td>
</tr>

<!-- spacer td로 열 간격 -->
<td width="20" style="width: 20px; font-size: 0; line-height: 0;">&nbsp;</td>

DON'T: margin에만 의존

<!-- 금지: table/td에 margin 사용 (Outlook에서 무시됨) -->
<table style="margin: 0 auto; margin-top: 24px;">
  <tr>
    <td style="margin-bottom: 16px;">내용</td>
  </tr>
</table>

Rule 9: 모바일 반응형

이메일도 반응형이 필요하다. <head> <style>@media 쿼리를 활용한다.

DO: 모바일 반응형 패턴

<!-- head의 style 블록 -->
<style>
  @media only screen and (max-width: 600px) {
    /* 전체 너비로 확장 */
    .email-container { width: 100% !important; }

    /* 2열 -> 1열 스택 */
    .stack-on-mobile {
      display: block !important;
      width: 100% !important;
    }

    /* 모바일에서 숨김 */
    .hide-on-mobile { display: none !important; }

    /* 모바일에서만 표시 */
    .show-on-mobile {
      display: block !important;
      max-height: none !important;
    }

    /* 텍스트 크기 조정 */
    .mobile-text-lg { font-size: 20px !important; line-height: 1.3 !important; }
    .mobile-padding { padding: 16px !important; }

    /* 이미지 전체 너비 */
    .full-width-image img { width: 100% !important; height: auto !important; }
  }
</style>

<!-- 2열 레이아웃 (모바일에서 스택으로) -->
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="600">
  <tr>
    <td class="stack-on-mobile" width="280" style="width: 280px; padding: 16px;">
      왼쪽 콘텐츠
    </td>
    <td class="stack-on-mobile" width="280" style="width: 280px; padding: 16px;">
      오른쪽 콘텐츠
    </td>
  </tr>
</table>

모바일/데스크탑 전용 콘텐츠

<!-- 데스크탑에서만 표시 -->
<tr class="hide-on-mobile">
  <td>데스크탑 전용 콘텐츠</td>
</tr>

<!-- 모바일에서만 표시 (기본: max-height:0; overflow:hidden) -->
<tr class="show-on-mobile" style="display: none; max-height: 0; overflow: hidden; mso-hide: all;">
  <td>모바일 전용 콘텐츠</td>
</tr>

Rule 10: 구분선 및 장식 요소

CSS border<hr>은 이메일 클라이언트마다 다르게 렌더링된다. 테이블 셀로 구분선을 만든다.

DO: 테이블 기반 구분선

<!-- 가로 구분선 -->
<tr>
  <td
    bgcolor="#e5e7eb"
    style="background-color: #e5e7eb; height: 1px; font-size: 0; line-height: 0; mso-line-height-rule: exactly;"
  >
    &nbsp;
  </td>
</tr>

<!-- 여백 + 구분선 -->
<tr>
  <td style="padding: 0 32px;">
    <table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
      <tr>
        <td bgcolor="#e5e7eb" style="background-color: #e5e7eb; height: 1px; font-size: 0; line-height: 0;">&nbsp;</td>
      </tr>
    </table>
  </td>
</tr>

DON'T: hr 태그 또는 border 속성으로 구분선

<!-- 금지: hr은 클라이언트별 스타일 불일치 -->
<hr style="border: 1px solid #e5e7eb;" />

<!-- 금지: border-bottom으로 구분선 -->
<td style="border-bottom: 1px solid #e5e7eb;">내용</td>

Rule 11: 텍스트 이메일 대비 (접근성)

HTML 이메일은 반드시 텍스트 버전과 함께 발송한다(멀티파트 MIME). 이미지 차단 시에도 내용 전달이 가능해야 한다.

  • 모든 이미지에 의미 있는 alt 텍스트 작성
  • 버튼/CTA는 텍스트 링크 형태로도 제공
  • 중요 정보를 이미지에만 담지 않는다 (이미지 차단 시 소실)

Rule 12: Outlook 전용 조건부 주석 패턴

<!-- Outlook 전용 콘텐츠 -->
<!--[if mso]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
  <tr>
    <td style="width: 600px;">
<![endif]-->

<!-- 비-Outlook 콘텐츠 -->
<!--[if !mso]><!-->
<div style="max-width: 600px;">
<!--<![endif]-->

<!-- ... 공통 콘텐츠 ... -->

<!--[if !mso]><!-->
</div>
<!--<![endif]-->

<!--[if mso]>
    </td>
  </tr>
</table>
<![endif]-->

금지사항 요약 (Anti-patterns)

금지 항목 대안
display: flex / display: grid <table> 레이아웃
position: absolute/fixed 테이블 레이아웃으로 배치
background-image (배경) bgcolor + background-color
border-radius (Outlook) VML <v:roundrect>
3자리 HEX (#fff) 6자리 HEX (#ffffff)
rgb() / rgba() / hsl() 6자리 HEX
웹 폰트 (@font-face, Google Fonts) 시스템 폰트 스택
em / rem 단위 px 단위
margin (table/td) padding + spacer td/tr
<hr> 구분선 bgcolor td (height: 1px)
이미지 상대 경로 절대 경로 (https://)
<img> display 미설정 style="display: block;"
CSS 클래스만으로 스타일 인라인 스타일 + 클래스 병행
!important 남용 클라이언트별 조건부 주석 활용

자주 하는 실수 TOP 5

1. Outlook에서 버튼이 사각형으로 표시됨

border-radius는 Outlook Word 렌더러에서 무시된다. VML 조건부 주석으로 반드시 대응한다. (Rule 7 참조)

2. 이미지가 차단되었을 때 레이아웃 붕괴

이미지에 width, height, display: block을 모두 설정하지 않으면, 이미지 차단 시 레이아웃이 무너진다.

<!-- 반드시 width/height/display:block 명시 -->
<img src="..." alt="..." width="600" height="200"
     style="display: block; width: 100%; max-width: 600px; height: auto; border: 0;" />

3. Outlook에서 줄 간격이 너무 좁거나 넓음

Outlook은 line-height 기본값이 다르다. 모든 <td>line-height를 명시하고 mso-line-height-rule: exactly를 추가한다.

<td style="font-size: 15px; line-height: 24px; mso-line-height-rule: exactly;">
  텍스트 내용
</td>

4. Gmail 앱에서 스타일이 전혀 적용되지 않음

Gmail 앱은 <head> <style> 블록을 완전히 제거한다. 레이아웃과 타이포그래피는 반드시 인라인 스타일로 작성한다.

5. 모바일에서 좁은 화면에 600px 고정 레이아웃

이메일 컨테이너에 width="600"과 함께 max-width: 600px을 설정하고, 모바일 반응형 클래스를 @media 쿼리로 관리한다.

<table class="email-container" width="600" style="width: 600px; max-width: 600px;">
@media only screen and (max-width: 600px) {
  .email-container { width: 100% !important; }
}