Files
claude-instructions/.claude/rules/markup/email-html-table.md

753 lines
21 KiB
Markdown

---
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: 표준 이메일 골격
```html
<!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: 불완전한 골격
```html
<!-- 금지: 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열 레이아웃 (테이블 중첩)
```html
<!-- 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: 헤더 / 본문 / 푸터 섹션 구조
```html
<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 사용
```html
<!-- 금지: 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: 인라인 스타일 사용
```html
<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: 클래스 기반 스타일
```html
<!-- 금지: 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 이중 설정
```html
<!-- 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 사용
```html
<!-- 금지: Outlook에서 렌더링 안 됨 -->
<td style="background-color: rgba(26, 86, 219, 0.9);">내용</td>
<td style="color: #fff;">내용</td>
```
---
### Rule 5: 폰트 및 타이포그래피
#### 웹 안전 폰트 스택 (한국어 지원)
```html
<!-- 한국어 지원 폰트 스택 -->
<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: 올바른 타이포그래피
```html
<!-- 제목 -->
<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 단위 사용
```html
<!-- 금지: 웹 폰트 (대부분 이메일 클라이언트에서 fallback으로 치환됨) -->
<td style="font-family: 'Pretendard', sans-serif;">내용</td>
<!-- 금지: em 단위 (기준값이 클라이언트마다 다름) -->
<p style="font-size: 1em; line-height: 1.5em;">내용</p>
```
---
### Rule 6: 이미지
#### DO: 올바른 이미지 태그
```html
<!-- 모든 필수 속성 포함 -->
<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: 잘못된 이미지 사용
```html
<!-- 금지: 상대 경로 사용 -->
<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 포함)
```html
<!-- 버튼 래퍼 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만으로 구현
```html
<!-- 금지: 이미지 버튼 (이미지 차단 시 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로 간격 조절
```html
<!-- 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에만 의존
```html
<!-- 금지: 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: 모바일 반응형 패턴
```html
<!-- 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>
```
#### 모바일/데스크탑 전용 콘텐츠
```html
<!-- 데스크탑에서만 표시 -->
<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: 테이블 기반 구분선
```html
<!-- 가로 구분선 -->
<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 속성으로 구분선
```html
<!-- 금지: 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 전용 조건부 주석 패턴
```html
<!-- 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`을 모두 설정하지 않으면, 이미지 차단 시 레이아웃이 무너진다.
```html
<!-- 반드시 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`를 추가한다.
```html
<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` 쿼리로 관리한다.
```html
<table class="email-container" width="600" style="width: 600px; max-width: 600px;">
```
```css
@media only screen and (max-width: 600px) {
.email-container { width: 100% !important; }
}
```