나는 이메일 검증 라이브러리를 만들고 npm에 배포했습니다. 여기 내가 배운 모든 것을 정리합니다.
Source: Dev.to
이야기
지난 몇 주 동안 이메일 검증 라이브러리를 처음부터 직접 만들고 npm에 배포했습니다. 세상이 또 다른 npm 패키지를 절실히 필요로 해서가 아니라, 이메일 검증이 실제로 어떻게 동작하는지 깊이 이해하고 싶었기 때문입니다. 기존 솔루션들이 만족스럽지 못했기에 직접 만들기로 결심했습니다.
이 글에서 저는 다음을 공유합니다:
- 제가 만든 이유
- 배운 점
- 대안보다 3배 빠른 성능을 구현하게 만든 기술적 결정들
- 같은 접근 방식을 활용해 여러분도 npm 패키지를 만들 수 있는 방법
그럼 바로 들어가 보겠습니다…
What I’m Going to Cover
- 왜 이 프로젝트를 시작했는가
- 대부분의 개발자가 모르는 이메일 검증의 5계층
- 경쟁 제품보다 3배 빠르게 만든 방법
- 기술 스택 선택 (그리고 그 이유)
- 첫 npm 패키지 배포 방법
- 다음에 다르게 할 점
왜 또 다른 이메일 검증기를 만들었을까?
프로젝트에서 deep-email-validator를 사용하고 있었어요. 동작은 했지만 몇 가지 문제가 눈에 띄었습니다:
- TypeScript 타입이 오래됐음 (여전히 3.8 사용)
- 대량 검증 지원이 없음
- 캐시가 없어 같은 이메일을 두 번 검증하면 모든 작업을 다시 수행함
- 오류 메시지가 “Invalid email” 같은 일반 문자열임
- 정규식 검증이 RFC 5322를 준수하지 않음
나는 생각했죠, “뭐, 더 나은 걸 만드는 건 그렇게 어려울까?”
유명한 마지막 말이죠. 실제로 이메일 검증은 대부분이 생각하는 것보다 훨씬 복잡합니다—바로 그 때문에 이 프로젝트를 만들 가치가 있었던 겁니다.
Source: …
이메일 검증의 5단계
대부분의 개발자는 이메일 검증을 단순히 정규식 검사라고 생각합니다. 이는 올바른 검증의 20 % 정도에 불과합니다. 실제 서비스에 적합한 검증기는 다음을 확인해야 합니다:
레이어 1 – 정규식 (형식 검증)
이메일이 이메일처럼 보이나요? RFC 5322를 따라야 합니다.
기술적으로 유효한 주소 예시:
"john doe"@example.com(인용 문자열)user+tag@example.com(플러스 주소)user@[192.168.1.1](IP‑주소 도메인)
많은 Stack‑Overflow 정규식은 이 중 절반을 거부합니다.
레이어 2 – 오타 감지
user@gmial.com은 구문적으로는 유효하지만 Gmail은 gmial.com에 존재하지 않습니다.
이 레이어는 흔한 오타를 잡아내고 “gmail.com을(를) 의미하셨나요?”와 같이 교정을 제안합니다.
레이어 3 – 일회용 이메일 감지
Mailinator, Guerrillamail, 10 Minute Mail…
일회용 이메일 서비스는 40 000개가 넘습니다. 이를 차단하지 않으면 데이터베이스가 가짜 사용자로 가득 찹니다.
레이어 4 – MX 레코드 검증
도메인이 정상처럼 보여도 메일 서버가 있나요?
MX 레코드에 대한 DNS 조회를 통해 해당 도메인이 이메일을 받을 수 있는지 확인합니다. MX가 없으면 → 무효.
레이어 5 – SMTP 검증
최종 보스: 메일 서버에 연결해 “이 메일함이 존재하나요?”를 물어봅니다.
네트워크 호출 때문에 느리고, 때때로 서버가 검증을 차단해 신뢰성이 떨어질 수 있지만, 확실한 결과가 필요할 때는 가장 좋은 방법입니다.
3배 빠르게 만들기
원래 deep-email-validator는 이메일을 순차적으로 검증하고, 캐시가 없으며 DNS와 SMTP 검사를 위해 매번 네트워크에 접근합니다. 저는 5초 이내에 100개의 이메일을 처리하고 싶었습니다.
솔루션 1 – 동시 처리
동시성을 설정하여 여러 이메일을 병렬로 검증합니다:
const result = await validateBulk(emails, {
concurrency: 10,
onProgress: (completed, total) => {
console.log(`Progress: ${completed}/${total}`);
},
});
10개의 동시 검증 ≈ 10배 빠른 대량 처리.
솔루션 2 – 내장 속도 제한
메일 서버를 과도하게 호출하면 블랙리스트에 오를 수 있습니다. 저는 토큰‑버킷 제한자를 추가했습니다:
await validateBulk(emails, {
rateLimit: {
perDomain: { requests: 10, window: 60 }, // 도메인당 1분에 10 요청
global: { requests: 100, window: 60 }, // 전역적으로 1분에 100 요청
},
});
성능을 유지하면서 남용을 방지합니다.
솔루션 3 – 조기 종료
정규식이 실패하면 MX 레코드를 확인할 필요가 없습니다. 조기 종료 옵션은 첫 번째 실패 시 검증을 중단하여 잘못된 이메일을 바로 거부합니다:
- 💻 GitHub:
- 📚 Docs:
다음은?
I’m planning to add:
- In‑memory LRU caching (v1.1)
- Enhanced reputation scoring with configurable weights
- CLI tool for quick validations
- Maybe a browser build
If you found this useful, star the repo on GitHub—it helps more than you’d think. And if you build something cool with it, let me know; I’d love to see what you create.