TELEPASI

검색하기 전에 통하다

Resend로 회원가입·비밀번호 찾기 메일 보내기 ( 2가지 방식 설명 )

강병우
2026.08.18 👁️ 49

이 글은 회원가입 확인 메일비밀번호 찾기 메일만 다룹니다.

앱(웹)은 Supabase Auth(GoTrue)에 “가입해 주세요”, “재설정 메일 보내 주세요”만 요청하고, 실제 발송은 Auth의 SMTP가 하는 경우를 Auth 템플릿 방식이라고 합니다.
앱(웹)이 static/email/template 파일로 본문을 만들어 Resend API로 보내는 경우를 파일 템플릿 방식이라고 합니다.

예시 주소(설명용):

  • 웹: https://example.com
  • Auth API: https://sb.example.com
  • 발신: noreply@example.com

아래 현재 서버 절만 telepasi.com, sb.telepasi.com을 씁니다.
API 키·SMTP 비밀번호는 게시물이나 Git에 넣지 마세요.


한 줄로 이해하기

Auth 템플릿 방식은 우체국(Auth)이 편지지까지 써서 보냅니다.
파일 템플릿 방식은 우리가 편지지를 써서 우체국(Resend)에 맡깁니다.

Auth 템플릿 방식 파일 템플릿 방식
누가 메일을 쓰나 Auth (Confirm signup / Reset password) 앱(웹) (static/email/template)
어떻게 보내나 Auth SMTP (Resend SMTP로 연결 가능) Resend API
가입 확인 템플릿 Confirm signup signup-confirm.html + .txt
비밀번호 찾기 템플릿 Reset password password-reset.html + .txt
치환 {{ .ConfirmationURL }} {{confirm_url}} / {{reset_url}}
가입 링크를 누르면 /auth/callback → 바로 로그인 /api/auth/confirm-email → 승인만, /login에서 다시 로그인
비번 링크를 누르면 /update-password /update-password (같음)

.txt는 HTML을 못 보는 메일용 텍스트 본문입니다.


Auth 템플릿 방식 — 앱(웹)은 요청만, 발송은 Auth

웹 저장소에는 가입·비번용 HTML이 없습니다. 본문은 Auth 대시보드 템플릿입니다.

flowchart LR
  U[사용자] --> W[example.com<br/>/signup · /reset-password]
  W --> JS[Supabase JS]
  JS --> A[sb.example.com<br/>GoTrue]
  A --> S[SMTP]
  S --> M[메일함]
  M --> L[링크 클릭]
  L --> C["/auth/callback"]
  L --> P["/update-password"]
sequenceDiagram
  participant U as 사용자
  participant W as example.com
  participant A as GoTrue
  participant S as SMTP
  participant M as 메일함

  U->>W: /signup 제출
  W->>A: auth.signUp()
  A->>A: 미인증 계정 + Confirm signup
  A->>S: SMTP 발송
  S->>M: 확인 메일
  W->>U: 메일 확인 안내 → /login
  U->>M: 링크 클릭
  M->>A: /auth/v1/verify
  A->>W: /auth/callback?code=...
  W->>A: exchangeCodeForSession
  W->>U: 로그인 완료

회원가입

  • URL: /signup
  • 호출: supabase.auth.signUp()
await supabase.auth.signUp({
	email,
	password,
	options: {
		data: { site_id: 'example', full_name: fullName },
		emailRedirectTo: `${window.location.origin}/auth/callback`
	}
});
  1. 이름·이메일·비밀번호를 넣습니다. 비밀번호는 6자 이상, 두 칸이 같아야 합니다.
  2. 「회원가입이 완료되었습니다! 이메일을 확인하여 인증을 완료해주세요.」
  3. 3초 뒤 /login으로 이동합니다.
  4. 메일 링크 → /auth/callback
  5. PKCE codeexchangeCodeForSession()으로 바꿔 세션을 만듭니다.
  6. site_access에 사이트 권한을 넣습니다.
  7. 메일을 열기 전에 로그인하면 「이메일 인증이 필요합니다.」

비밀번호 찾기

sequenceDiagram
  participant U as 사용자
  participant W as example.com
  participant A as GoTrue
  participant S as SMTP
  participant M as 메일함

  U->>W: /reset-password
  W->>A: resetPasswordForEmail()
  A->>A: Reset password 템플릿
  A->>S: SMTP 발송
  S->>M: 재설정 메일
  U->>M: 링크 클릭
  M->>A: /auth/v1/verify
  A->>W: /update-password
  W->>A: 세션 확보
  U->>W: 새 비밀번호
  W->>A: updateUser password
  W->>U: /login
  • URL: /reset-password
  • 호출: supabase.auth.resetPasswordForEmail()
await supabase.auth.resetPasswordForEmail(email, {
	redirectTo: `${window.location.origin}/update-password`
});
  1. 이메일을 넣고 「재설정 링크 받기」
  2. GoTrue가 recovery 메일 발송
  3. 링크 → /update-password
  4. recovery 세션 확보 (getSession / hash setSession / PKCE)
  5. updateUser({ password })
  6. /login으로 이동

인증·복구 링크는 먼저 Auth verify를 거친 뒤 앱(웹)의 redirectTo로 돌아옵니다.

MAILER_URLPATHS_CONFIRMATION=/auth/v1/verify
MAILER_URLPATHS_RECOVERY=/auth/v1/verify

예: https://sb.example.com/auth/v1/verify/auth/callback 또는 /update-password

Auth에 넣을 값

항목
ENABLE_EMAIL_SIGNUP true
ENABLE_EMAIL_AUTOCONFIRM false
DISABLE_SIGNUP false
SITE_URL https://example.com
허용 redirect /auth/callback, /update-password (www 쓰면 둘 다)

권장 SMTP(Resend):

SMTP_HOST=smtp.resend.com
SMTP_PORT=465
SMTP_USER=resend
SMTP_PASS=re_xxxxxxxx
SMTP_ADMIN_EMAIL=noreply@example.com
SMTP_SENDER_NAME=Example

SMTP_USER는 이메일 주소가 아니라 문자열 resend입니다.

  • Confirm signup → {{ .ConfirmationURL }}
  • Reset password → {{ .ConfirmationURL }}

www에서 시작하면 redirect도 www입니다. allow list에 맞추세요.


파일 템플릿 방식 — 파일이 본문

앱(웹)이 서버 API를 부르고, 서버가 파일을 읽어 Resend API로 보냅니다.

static/email/template/
  signup-confirm.html
  signup-confirm.txt
  password-reset.html
  password-reset.txt
flowchart LR
  U[사용자] --> W[example.com]
  W --> API["/api/auth/signup<br/>/api/auth/reset-password"]
  API --> T[static/email/template]
  T --> R[Resend API]
  R --> M[메일함]
  M --> C["/api/auth/confirm-email"]
  M --> P["/update-password"]
sequenceDiagram
  participant U as 사용자
  participant W as example.com
  participant API as 앱(웹) API
  participant A as Auth Admin
  participant R as Resend API
  participant M as 메일함

  U->>W: /signup
  W->>API: POST /api/auth/signup
  API->>A: createUser 미인증
  API->>API: signup-confirm.html + .txt
  API->>R: sendMail
  R->>M: 승인 메일
  U->>M: 링크 클릭
  M->>API: /api/auth/confirm-email
  API->>A: email_confirm true
  API->>U: /login 에서 다시 로그인
sequenceDiagram
  participant U as 사용자
  participant W as example.com
  participant API as 앱(웹) API
  participant A as Auth Admin
  participant R as Resend API
  participant M as 메일함

  U->>W: /reset-password
  W->>API: POST /api/auth/reset-password
  API->>A: generateLink recovery
  API->>API: password-reset.html + .txt
  API->>R: sendMail
  R->>M: 재설정 메일
  U->>M: 링크 클릭
  M->>W: /update-password
  U->>W: 새 비밀번호
  W->>A: updateUser password
  W->>U: /login

emailTemplateLoader.js{{이름}}을 바꾸고, sendMail()이 HTML과 .txt를 함께 보냅니다.

회원가입

  1. /signupPOST /api/auth/signup
  2. Admin createUser — 아직 미인증
  3. 승인 토큰(24시간)을 signup-confirm에 넣음
  4. Resend API 발송. 실패하면 방금 만든 계정 삭제
  5. 링크: /api/auth/confirm-email?uid=...&token=...
  6. 승인만 하고 /login — 자동 로그인 없음

템플릿 변수: name, email, confirm_url, site_name, site_url, year

비밀번호 찾기

  1. /reset-passwordPOST /api/auth/reset-password
  2. generateLink({ type: 'recovery' })로 주소만 받음
  3. {{reset_url}}에 넣음
  4. Resend API 발송
  5. /update-password → 새 비밀번호 → /login

템플릿 변수: name, reset_url, site_name, site_url, year

PUBLIC_SUPABASE_URL=https://sb.example.com
RESEND_API_KEY=re_xxxxxxxx
FROM_EMAIL=noreply@example.com

현재 서버 (telepasi.com) — Auth 템플릿 방식

회원가입·비밀번호 찾기는 앱(웹) → GoTrue → SMTP 입니다.

flowchart LR
  U[사용자] --> W[telepasi.com]
  W --> JS[Supabase JS]
  JS --> A[sb.telepasi.com<br/>GoTrue]
  A --> S[SMTP]
  S --> M[메일함]
  M --> C["/auth/callback"]
  M --> P["/update-password"]
용도 앱(웹) allow list
회원가입 인증 {origin}/auth/callback ADDITIONAL_REDIRECT_URLS
비밀번호 재설정 {origin}/update-password 동일

www.telepasi.com에서 시작하면 redirect도 www입니다.
가입 메타데이터는 site_id: telepasi이고, 인증 후 site_access에 넣습니다.

항목
ENABLE_EMAIL_SIGNUP true
ENABLE_EMAIL_AUTOCONFIRM false
DISABLE_SIGNUP false
SITE_URL https://telepasi.com
허용 redirect telepasi.com/*, www.telepasi.com/*
MAILER_URLPATHS_CONFIRMATION=/auth/v1/verify
MAILER_URLPATHS_RECOVERY=/auth/v1/verify

링크는 https://sb.telepasi.com/auth/v1/verify를 거친 뒤 앱(웹)으로 돌아옵니다.

지금 SMTP는 개발용 기본값

/root/supabase/docker/.env 기준입니다.

변수 현재 값 의미
SMTP_HOST supabase-mail Docker 내부 이름
SMTP_PORT 2500
SMTP_USER fake_mail_user 개발용 기본값
SMTP_PASS fake_mail_password 개발용 기본값
SMTP_ADMIN_EMAIL admin@example.com
SMTP_SENDER_NAME fake_sender

docker-compose.yml에 메일 컨테이너가 없고 Auth만 이 값을 들고 있습니다.
운영 SMTP로 바꾸지 않으면 실제 메일함으로 거의 가지 않습니다.

GOTRUE_MAILER_EXTERNAL_HOSTS에 호스트가 없어
X-Forwarded-Host(sb.telepasi.com)를 메일 링크에 쓰지 않음
  • 앱(웹) signup / reset → GoTrue 호출: 됨
  • autoconfirm false, redirect allow list: 됨
  • SMTP 개발용 기본값: 실제 수신 불가 가능성 큼
  • GOTRUE_MAILER_EXTERNAL_HOSTS 없음: 메일 링크 도메인 경고

/auth/callback에서 OTP 만료 시 magic link 재발송 UI가 있습니다.

API 역할
POST /api/admin/resend-verification 이메일 인증 수동 완료
POST /api/admin/reset-password 관리자 비밀번호 재설정

메일이 안 오면

cd /root/supabase/docker
docker compose logs --tail=100 auth
docker compose logs auth | rg 'user_signedup|user_recovery_requested|smtp'
  1. Auth SMTP를 Resend로 변경 (smtp.resend.com, 사용자 resend, 비밀번호는 API 키, 발신 noreply@telepasi.com)
  2. GOTRUE_MAILER_EXTERNAL_HOSTS=telepasi.com,www.telepasi.com
  3. Auth 컨테이너 recreate
cd /root/supabase/docker
docker compose up -d --force-recreate auth

자주 생기는 문제

메일이 안 온다

  • Auth 템플릿 방식: SMTP가 supabase-mail / fake_mail_* 인지
  • 파일 템플릿 방식: 웹 RESEND_API_KEY가 있는지
  • ENABLE_EMAIL_AUTOCONFIRM=true이면 확인 메일을 안 보냄

링크를 눌렀는데 오류

  • allow list에 /auth/callback, /update-password (www 포함)
  • 파일 템플릿 방식 가입 링크 만료(24시간) 또는 재사용
  • 링크는 보통 한 번만 유효

로그인 시 「이메일 인증이 필요합니다」

  • 확인 메일 버튼을 아직 누르지 않음

적용 전에 볼 것

Auth 템플릿 방식

  • Auth SMTP = 실제 발송기 (권장: Resend SMTP)
  • Confirm signup / Reset password에 {{ .ConfirmationURL }} 유지
  • Redirect URL에 /auth/callback, /update-password
  • GOTRUE_MAILER_EXTERNAL_HOSTS에 웹 도메인
  • Auth 컨테이너 recreate

파일 템플릿 방식

  • signup-confirm.html + .txt, password-reset.html + .txt
  • RESEND_API_KEY, FROM_EMAIL
  • 가입 /api/auth/signup, 비번 /api/auth/reset-password

telepasi.com 지금

  • 앱(웹) 호출·autoconfirm·redirect는 되어 있음
  • 다음 작업은 Auth SMTP를 Resend로 교체

주파수 소통방 (0)

로딩 중...