LoRA 학습 프로젝트를 진행 하며 학습 결과를 사용자에게 email로 전송 해줘야 하는 기획이 생겼다. 이를 위해 email form을 html으로 생성하여 Backend에 전달 해 주었다.
여기서 문제가 발생 했는데 해당 form을 이용하여 사용자에게 전달 된 메일을 확인 해보니 <그림 1>과 같이 최초 사용자가 사용했던 내용과 너무 달랐다.
<그림 1>
해결 하기 위해 3가지를 알아 보고자 한다.
- 왜 이런 일이 벌어지는가
- 그럼 어떻게 해야 하나
- 테스트는?
Backend에서 html로 작성된 template을 사용해야 하기 때문에 하나의 html에 모든 코드가 들어가야 했다. 그렇기 때문에 아래의 구조로 코드를 작성했다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" as="style" crossorigin href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.8/dist/web/variable/pretendardvariable.css" />
<style>
</style>
<title>Document</title>
</head>
<body>
<header class="box">
...
</header>
<main>
...
</main>
<footer>
...
</footer>
</body>
</html>요
div와 css를 이용한 layout
그리고 이를 감싼
일반 적인 코드인데 다 Email 에 넣기에는 모두 적절하지 않다. 몇 가지 이유가 있는데 먼저 email의 동작을 생각해 보면 이해가 가고 조치가 납득이 간다.
이메일은 기본적으로 브라우저를 통해 서비스 된다. 이에 사용자는 전송된 이메일을 브라우저를 통해서 읽게 된다. 우리가 익히 알고 있듯 브라우저는 html 컨텐츠를 다운로드 하면 읽어 들이고 화면상에 랜더링 한다. 이때 html에 포함된 script 또한 실행 된다. 이런 특징은 3가지 문제를 발생 시킬 수 있다.
이메일 컨텐츠에 악성 코드가 포함되어 있다면 사용자의 의지와 관계없이 스크립트가 실행 되어 문제가 될 수 있다.
또, 피싱에 취약하다. 우리는 스크립트를 이용해서 사용자의 정보를 확인하거나, 내가 원하는 사이트로 리디렉션 시킬 수 있다. 동일한 동작을 이메일 코드에 포함 시킨다면 쉽게 피싱이 가능하다.
불특정 사용자들이 사용하는 브라우저는 Vender도 다양하고 그에 따른 버전도 다양하여 사용자에게 보여지는 컨텐츠가 일관 적이지 않을 수 있고 내용의 유실이 있을 수도 있다. 그렇기 때문에 최대한 보수 적인 마크업 코드가 필요하다.
이메일은 앱으로서 소비하기 보다 컨텐츠 확인용으로 사용하기 마련이다. 그렇기 때문에 빠르게 로딩되어 사용자가 확인 할 수 있어야 한다. 그렇기 위해서는 html 이외에 다운로드가 필요한 컨텐츠(이미지, 폰트 등)은 지양하는게 유리하다.
style 태그 내부의 class 이용한 스타일링은 결국 CSSOM에 파싱하여 업데이하는 비용이 들고 더 나아가 재사용성과 편안함? 때문에 좀 스타일에 욕심을 내게 되고 랜더링 비용을 더 소모하게 할 수 있다.
기본적으로 head 태그를 날려 버린다. 심지어 body를 날려 버리기도 한다. head에는 script, style, link 등의 컨텐츠에 도움이 되는 태그들이 존재 하고 이를 다 날려 버려 발생 할 수 있는 경우의 수를 원천 차단한다.
또한 태그 attribute로 존재하는 onclick과 같은 이벤트 핸들러 삭제한다.
VARCO Art LoRA 에 의견 보내기위와 같은 간단한 코드를 삽입 했었으나 받아 본 이메일에서는 <그림 2>와 같이 삭제 되어 있었다.
<그림 2>
기본적으로는 브라우저의 호환성을 따라가고 이메일 Vender에서 별도로 처리하는 부분은 거의 없다. 브라우저 버전이 같다면, 모바일, 데스크탑 보이는 바는 같다. <그림 2>에서 class=”btn-opinion” => class=”x_btn-opinion” 이라고 변경 된 것 빼고는 별도의 조치는 없다. 이 또한 스타일에 영향을 끼치는 부분은 아니다.
다만, outlook의 경우 브라우저가 아닌 데스크탑 어플리케이션을 사용하는 경우 <그림 3>과 같은 경우 문제가 된다. 신 버전과, 구 버전의 차이가 있다. 이는 앱에서 사용하는 브라우저의 차이로 보인다.
<그림 3>
최소한의 스타일과 스크립트를 실행하지 않고 별도 download로 없도록 하여 메일을 확인 할 때 컨텐츠가 빠르게 랜더링 한다. 당연하게도 일반 html템플릿과 이메일 템플릿에 맞게 수정한 버전의 차이가 실제 라이트 하우스에서 확인 가능한데 <그림 4>와 같다.
<그림 4>
위에서 설명 했던 보안 문제로 스크립트가 동작 할 수 없으니 이메일 템플릿에 스크립트는 넣는 일은 없어한다. 결국 이메일에서 동작하는 기능은 <a> 태그를 이용한 하이퍼링크만 허용 된다.
<a> 태그 사용 시 target=”_blank” 를 이용해 새창을 사용하는 경우 에도 보안 강화를 위해 아래와 noopener, noreferrer 옵션을 주는 편이 좋다.
<a href="https://xxx.xxxx.com" target="_blank" rel="noopener noreferrer">
window.opener 를 이용하면 나를 띄운 부모에 접근이 가능해 진다. 이를 막는 옵션이다.
결국 부모 브라우저 컨텍스트에 액세스 권한이 없는 새탭이 뜨게 된다.
하이퍼링크로 이동할 때 참조자 정보 즉 링크 클릭한 사람의 경로를 알 수 없게 해준다.
html 프로토콜에는 해더에 referrer를 통해 해당 페이지를 요청한 이전 페이지의 주소를 알 수 있고 이를 웹 서버에 전송 해준다. 이를 막는 옵션이다.
<head>태그가 사리지기 때문에 class를 사용 할 수 없다 html의 style 속성에 스타일을 기제 하는 방식으로 스타일을 정의 해야 한다.
색상 지정은 rgb 보다 hex를 사용하는 편이 좋다.
이미지를 사용하는 경우는 이미지가 막히는 경우가 더러 있기 때문에 alt를 이용해 설명을 다는 것이 좋다.
width는 지정 되는 편이 안전하고 보통 800px 미만이 좋다고 한다.
<body> 태그 안에 전체를 한번 감싸는 <div>를 싸주는 편이 좋다. body태그도 허용하지 않는 이메일 서비스도 있다.
<table> 이용좀 고될 수 있지만 table 태그를 지향하는 편이 좋다. 브라우저를 사용하기 때문에 호환성에 문제가 있다. table 요소가 아닌 경우 CSS 가 적용 되지 않는 경우가 있다. 이를 테면 <div>에 padding을 정의 해도 적용 되지 않는 경우가 있다. 이중에서도 나중에 생긴 마크업인 <thead>, <tbody> 등을 이용하기 보다, <table><tr><td> 로 구현 하는 편이 좋다.
table은 기본 적으로 display; table 이기 때문에 사이즈를 조절이 필요하면 display: block 등을 해주고 사용하자.
아래와 같은 단순한 header 용 마크업이 있다고 해보자.
<header style="width: 100%; padding: 23px; background-color: #6a29d3;">
<span style="color: #FFF; font-variant-numeric: lining-nums tabular-nums; font-size: 20px; font-style: normal; font-weight: 700; line-height: normal;">
학습 결과 알림
</span>
</header>
이를 table로 변경 하자면 아래와 같이 변경 가능하다.
<table width="100%" cellpadding="0" cellspacing="0" style="border-collapse: collapse;">
<tr>
<td style="padding: 23px; background-color: #7844CC; color: #FFF; text-align: center; font-size: 20px; font-weight: 700;">
학습 결과 알림
</td>
</tr>
</table>
<table> 태그를 적용할 경우, 위 코드 처럼초기화를 하고 사용하는 것이 좋다.
border : 선의 유무. 1은 있음, 0은 없음.
cellpadding : 셀 내부 여백
cellspacing : 셀 사이의 너비
width : 테이블의 가로 너비
이게 너무 힘들다면 생성형 AI 가 쉽게 바꿔 준다. 먼저 스타일링을 하고 이후 생성형 AI에 변경 해달라고 하면 깔끔하게 다 바꿔 주니 AI 시대를 살아가는 우리는 이런 툴을 잘 사용하면 힘들이지 않고 빠르게 결과물을 뽑아 낼 수 있다.
테스트는 실제 이메일을 쏴보지 않는 이상 확인이 어렵고 이게 가장 확실한 방법인 것 같다.
지금은 실제 테스트 배드를 구현해도 좋으나 관리도 필요하고 로컬 서버이고 여러 이메일에 대한 테스트 환경 구현이 쉽지 않기 때문에 때문에 별도의 테스트 사이트를 이용하는 편이 좋다.
https://app.postdrop.io/templates
여기가 가장 괜찮았는데 내가 만든 폼을 먼저 보여주고 내가 원하는 이메일 계정으로 이메일 전송을 해준다.
이메일 템플릿을 만드는데 2가지가 가장 중요하다.
스크립트 사용 안됨
스타일은 inline 스타일로