Mailtrap 이메일 통합
Mailtrap의 Email API와 Sandbox를 사용하여 애플리케이션에 트랜잭션 이메일 전송을 추가하는 패턴입니다. 인증, 환경 분리 및 일반적인 전송 문제를 다룹니다.
활성화 시점
- "이메일 보내기" 기능 구현 (회원가입 확인, 비밀번호 재설정, 알림, 영수증)
- 개발/스테이징 환경에서 이메일이 도착하지 않는 문제 디버깅
- 프로젝트의 첫 이메일 전송 통합 설정
- Sandbox 분리 없이 이메일 API를 직접 호출하는 코드 검토
핵심 개념
Sandbox와 프로덕션 분리. Mailtrap은 Sandbox API를 제공하여 이메일을 전달하지 않고 캡처합니다. 개발/스테이징 환경에서 test 이메일이 실제 수신자에게 전달되지 않도록 합니다. 프로덕션 전송은 별도의 검증된 도메인 엔드포인트를 사용합니다. 개발 환경을 프로덕션 전송 엔드포인트로 설정해서는 안 됩니다.
인증. 요청 시 Authorization 헤더에 Bearer 토큰을 사용합니다. 토큰은 프로젝트별로 범위가 지정되며, Sandbox와 프로덕션은 일반적으로 다른 토큰을 사용합니다.
도메인 인증. 프로덕션 전송을 위해서는 DNS 레코드(SPF, DKIM, DMARC)를 통해 발송 도메인을 인증해야 합니다. 이 단계를 건너뛰면 이메일이 전달되지 않거나 스팸 폴더로 분류됩니다.
코드 예제
// Mailtrap Email API를 통한 프로덕션 전송
async function sendEmail(to: string, subject: string, html: string) {
const response = await fetch("https://send.api.mailtrap.io/api/send", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.MAILTRAP_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: { email: "[email protected]", name: "Your App" },
to: [{ email: to }],
subject,
html,
}),
});
if (!response.ok) {
throw new Error(`Email send failed: ${response.status}`);
}
return response.json();
}
// 동일한 호출, 프로덕션이 아닌 환경에서는 Sandbox로 라우팅
const MAILTRAP_ENDPOINT = process.env.NODE_ENV === "production"
? "https://send.api.mailtrap.io/api/send"
: `https://sandbox.api.mailtrap.io/api/send/${process.env.MAILTRAP_INBOX_ID}`;
안티 패턴
| 안티 패턴 | 문제점 | 대안 |
|---|---|---|
| 개발/테스트 환경에서 프로덕션 전송 엔드포인트 사용 | 실제 test 이메일이 실제 수신자에게 도달하여 스팸 신고 및 test 데이터 유출 위험 | 비프로덕션 환경은 Sandbox 엔드포인트로 라우팅 |
| API 토큰을 소스 코드에 하드코딩 | 버전 관리에 커밋될 경우 자격 증명 유출 위험 | 환경 변수 / 비밀 관리자에서 토큰 로드 |
| 도메인 인증 완료 전에 전송 | 이메일이 자동으로 실패하거나 스팸으로 분류 | 프로덕션 전송 활성화 전에 SPF/DKIM/DMARC 레코드 확인 |
| 전송 실패 시 재시도/오류 처리 부재 | 사용자에게 비밀번호 재설정 이메일이 전달되지 않는 등 알림 실패 발생 | 응답 상태 확인, 실패 로깅, 실행 가능한 오류 표시 |
모범 사례
- Sandbox와 프로덕션 토큰은 별도의 환경 변수에 저장하고, 절대 하나의 토큰을 여러 환경에서 공유하지 않음
- 이메일을 포함하는 프로덕션 출시 전에 발송 도메인의 DNS 레코드를 반드시 확인
- 전송 실패를 디버깅할 수 있도록 수신자, 템플릿, 타임스탬프, 응답 코드 등의 맥락과 함께 로깅
- 이메일 전송은 실패할 수 있는 네트워크 호출로 간주: try/catch로 감싸고 성공을 가정하지 않음
관련 스킬
api-and-interface-design, security-and-hardening, ci-cd-and-automation