우리 회원가입 중 12%가 가짜였던 이유 — 그리고 우리가 취한 조치

발행: (2026년 3월 7일 오전 06:10 GMT+9)
10 분 소요
원문: Dev.to

Source: Dev.to

지난 10월, 나는 ESP 대시보드를 열어 12.3 % 하드 바운스가 발생한 온보딩 이메일을 확인했다.

소프트 바운스가 아니다. “메일함 가득 찼다”도 아니다. 하드 550 거절 – 제공업체가 위협처럼 느껴지는 경고 메일을 보내게 만드는 종류다.

우리는 누구에게도 스팸을 보내지 않았다. 리스트를 스크래핑하지도 않았다. 이들은 방금 가입한 사용자들이다.

그때 깨달았다. 이것은 발송 문제가 아니라 가입 문제였다는 것을.

이메일이 반송될 때 실제로 일어나는 일

대부분의 개발자는 문제가 생길 때까지 SMTP 계층을 살펴보지 않는다. 나도 마찬가지였다.

서버가 메일을 보낼 때, 수신 도메인의 MX 레코드에 연결한다. 흐름은 보통 다음과 같다:

1. TCP connect
2. EHLO your-domain.com
3. MAIL FROM:
4. RCPT TO:

사서함이 존재하지 않으면 원격 서버는 다음과 같이 응답한다:

550 5.1.1 User unknown

그 거부는 보통 본문이 전송되기 전에 발생한다 – 내용도, HTML도 없고, 프로토콜 수준의 “거부”만 있다.

이러한 일이 충분히 자주 발생하면 발신 IP가 의심스러워 보이기 시작한다. 메일 제공업체는 이를 면밀히 추적한다. 높은 하드‑바운스 비율은 데이터 관리를 제대로 하지 못한다는 신호이며, 이는 메일 제공업체가 좋아하지 않는다.

왜 정규식과 더블 옵트‑인으로도 우리를 구하지 못했는가

우리의 첫 번째 시도는 예측 가능했다: 정규식 검증.

/^[^\s@]+@[^\s@]+\.[^\s@]+$/

명백한 쓰레기는 잡아내지만 fakeuser@gmail.com 같은 경우는 전혀 걸러내지 못한다.

다음으로 MX 검사를 추가했다. 도메인에 메일 서버가 없으면 거부한다. 이로 인해 일부 쓰레기 도메인은 사라졌지만, 실제 도메인에 존재하지 않는 주소는 여전히 허용된다.

그 뒤에 더블 옵트‑인을 도입했다. 더블 옵트‑인은 도움이 되지만, 반응형이다. 첫 번째 메시지는 여전히 전송한다. 만약 반송되면 이미 피해가 발생한 것이다. 사용자가 아무것도 클릭하기 전에 평판이 떨어진다.

우리는 데이터베이스에 저장되기 전에 잘못된 주소를 차단해야 했다.

해결책: 가입 시 실시간 메일함 확인

우리는 주소를 가입 순간에 검증하기로 했습니다 – 단순히 형식만 확인하거나 도메인 존재 여부만 확인하는 것이 아니라 실제 메일함을 확인합니다.

VerifiSaaS (https://verifisaas.com)를 사용하게 되었습니다. ZeroBounce와 NeverBounce 같은 다른 도구도 있지만, 우리는 CSV 워크플로우 없이 백엔드에 바로 들어갈 수 있는 API‑first 솔루션을 원했습니다.

다음은 현재 우리 Next.js API 라우트가 어떻게 생겼는지 보여줍니다:

// pages/api/signup.js
export default async function handler(req, res) {
  const { email, password } = req.body;

  const response = await fetch('https://api.verifisaas.com/v1/verify', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${process.env.VERIFISAAS_API_KEY}`
    },
    body: JSON.stringify({ email })
  });

  const result = await response.json();
  const { status, confidence_score, classification } = result;

  if (status === 'undeliverable') {
    return res.status(400).json({ error: 'That email address does not exist.' });
  }

  if (confidence_score < 0.6 || classification === 'risky') {
    return res.status(400).json({ error: 'Please use a valid email address.' });
  }

  return res.status(200).json({ success: true });
}

그게 전부입니다. 폼이 이 라우트로 POST되면 데이터베이스에 아무것도 쓰기 전에 검증합니다. 주소가 실패하면 바로 중단합니다 – 환영 이메일도, 반송도, 평판 손상도 없습니다.

배포 후 변화

  • 일주일 안에, 우리의 하드‑바운스 비율이 ≈12 %에서 <0.5 % 로 감소했습니다.
  • 이는 대략 10통 중 1통이 실패하던 것이 천 통당 약 4통으로 감소한 것입니다.
  • 우리 ESP가 경고 이메일 발송을 중단했습니다.
  • 발신자 점수가 다음 몇 주에 걸쳐 서서히 상승했습니다.
  • 온보딩 이메일 누락에 대한 지원 티켓이 감소했습니다.

더 큰 승리는 평판만이 아니었습니다.

  • 우리 데이터베이스가 정리되었습니다.
  • 마케팅 자동화가 스팸 계정 때문에 멈추는 일이 사라졌습니다.
  • 분석 결과가 더 신뢰할 수 있게 되었습니다.
  • 더 이상 가짜 사용자 위에 기능을 구축하지 않게 되었습니다.

이것은 v1에 포함됐어야 했습니다.

복잡해지는 부분

모두가 깔끔한 250 혹은 550 응답만 있는 것은 아닙니다.

  • Catch‑all 도메인은 SMTP 검사 단계에서 모든 주소를 받아들인 뒤, 나중에 메일을 조용히 버립니다. 모든 250을 유효한 것으로 처리하면 품질을 과대평가하게 됩니다. 우리는 Catch‑all을 자동 차단하지 않고 표시합니다. 일부 사용자에게는 이것으로 충분하지만, 위험도가 높은 가입의 경우 추가 확인을 요청합니다.
  • 일회용 이메일 제공업체는 또 다른 회색 영역입니다. B2B SaaS에서는 보통 의도가 낮은 경우가 많고, 소비자 앱에서는 정당한 프라이버시 선택이 될 수 있습니다. 우리는 이를 표시하고, 무조건 차단하기보다는 상황에 따라 판단합니다.
  • 성능 – 가입 양식에 트래픽 급증이 발생하고 실시간으로 모든 주소를 검증한다면 그 영향을 체감하게 됩니다. 우리는 기본적인 속도 제한과 검증 API가 타임아웃될 경우를 대비한 폴백 모드를 추가했습니다. 가입 흐름은 방어 장치 없이 단일 외부 호출에만 의존해서는 안 됩니다.

이것이 가치가 있을 때

  • 주당 몇 통의 이메일만 보내는 경우, 이는 크게 중요하지 않을 수 있습니다.
  • 유료 획득을 진행하거나 수천 명의 사용자를 온보딩하거나 수익과 연결된 트랜잭션 메일을 보내는 경우, 두 자릿수 반송률을 감당할 수 없습니다.

우리는 그 어려움을 직접 겪었습니다. 도메인 평판이 떨어진 후 전달성을 복구하는 것은 고통스럽습니다. 가장자리에서 나쁜 데이터를 방지하는 것이 훨씬 쉽습니다.

내가 다르게 할 일

나는 가입 검증을 처음부터 이메일 인프라의 일부로 다루었을 것이다.

우리는 이메일 문제가 전송 레이어에 있다고 생각했다. 그렇지 않았다. 그것은 입력 레이어에 있었다.

잘못된 데이터는 빠르게 퍼진다. 분석, 마케팅, 청구 및 지원 워크플로우를 오염시킨다. 한 번 들어가면, 정리하는 것은 악몽이다.

코딩을 즐기세요, 그리고 반송률이 0.5 % 이하가 되길 바랍니다!

0 조회
Back to Blog

관련 글

더 보기 »