Skip to content
Migrating from NextAuth.js v4? Read our migration guide.
가이드Configuring Custom HTTP Email Provider

HTTP 이메일

Resend, SendGrid, Postmark와 같은 내장된 HTTP 이메일 프로바이더가 있지만, 때로는 여러분만의 HTTP 엔드포인트를 사용하여 이메일을 보내고 싶을 수 있습니다.

이를 위해 커스텀 sendVerificationRequest 메서드를 사용하여 여러분만의 프로바이더를 작성할 수 있습니다. 단, email 타입 프로바이더는 반드시 데이터베이스 어댑터가 필요하다는 점을 잊지 마세요.

./auth.ts
import NextAuth from "next-auth"
import { sendVerificationRequest } from "./lib/authSendRequest"
 
export const { handlers, auth } = NextAuth({
  adapter,
  providers: [
    {
      id: "http-email",
      name: "Email",
      type: "email",
      maxAge: 60 * 60 * 24, // 이메일 링크는 24시간 후 만료됩니다.
      sendVerificationRequest,
    },
  ],
})

초기 설정을 완료한 후, sendVerificationRequest 함수를 작성해야 합니다. 아래는 사용자에게 링크가 포함된 텍스트 이메일을 보내는 간단한 버전입니다.

./lib/authSendRequest.ts
export async function sendVerificationRequest({ identifier: email, url }) {
  // 클라우드 이메일 프로바이더 API를 호출하여 이메일을 보냅니다.
  const response = await fetch("https://api.sendgrid.com/v3/mail/send", {
    // 본문 형식은 프로바이더에 따라 다르므로, 해당 문서를 참고하세요.
    body: JSON.stringify({
      personalizations: [{ to: [{ email }] }],
      from: { email: "noreply@company.com" },
      subject: "Sign in to Your page",
      content: [
        {
          type: "text/plain",
          value: `Please click here to authenticate - ${url}`,
        },
      ],
    }),
    headers: {
      // 인증 방식도 프로바이더마다 다르므로, 해당 문서를 참고하세요.
      Authorization: `Bearer ${process.env.SENDGRID_API}`,
      "Content-Type": "application/json",
    },
    method: "POST",
  })
 
  if (!response.ok) {
    const { errors } = await response.json()
    throw new Error(JSON.stringify(errors))
  }
}

아래는 더 발전된 sendVerificationRequest 함수의 예제로, 내장 함수의 버전입니다.

./lib/authSendRequest.ts
export async function sendVerificationRequest(params) {
  const { identifier: to, provider, url, theme } = params
  const { host } = new URL(url)
  const res = await fetch("https://api.resend.com/emails", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${provider.apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      from: provider.from,
      to,
      subject: `Sign in to ${host}`,
      html: html({ url, host, theme }),
      text: text({ url, host }),
    }),
  })
 
  if (!res.ok)
    throw new Error("Resend error: " + JSON.stringify(await res.json()))
}
 
function html(params: { url: string; host: string; theme: Theme }) {
  const { url, host, theme } = params
 
  const escapedHost = host.replace(/\./g, "​.")
 
  const brandColor = theme.brandColor || "#346df1"
  const color = {
    background: "#f9f9f9",
    text: "#444",
    mainBackground: "#fff",
    buttonBackground: brandColor,
    buttonBorder: brandColor,
    buttonText: theme.buttonText || "#fff",
  }
 
  return `
<body style="background: ${color.background};">
  <table width="100%" border="0" cellspacing="20" cellpadding="0"
    style="background: ${color.mainBackground}; max-width: 600px; margin: auto; border-radius: 10px;">
    <tr>
      <td align="center"
        style="padding: 10px 0px; font-size: 22px; font-family: Helvetica, Arial, sans-serif; color: ${color.text};">
        Sign in to <strong>${escapedHost}</strong>
      </td>
    </tr>
    <tr>
      <td align="center" style="padding: 20px 0;">
        <table border="0" cellspacing="0" cellpadding="0">
          <tr>
            <td align="center" style="border-radius: 5px;" bgcolor="${color.buttonBackground}"><a href="${url}"
                target="_blank"
                style="font-size: 18px; font-family: Helvetica, Arial, sans-serif; color: ${color.buttonText}; text-decoration: none; border-radius: 5px; padding: 10px 20px; border: 1px solid ${color.buttonBorder}; display: inline-block; font-weight: bold;">Sign
                in</a></td>
          </tr>
        </table>
      </td>
    </tr>
    <tr>
      <td align="center"
        style="padding: 0px 0px 10px 0px; font-size: 16px; line-height: 22px; font-family: Helvetica, Arial, sans-serif; color: ${color.text};">
        If you did not request this email you can safely ignore it.
      </td>
    </tr>
  </table>
</body>
`
}

이 커스텀 프로바이더를 통해 로그인하려면, 로그인 메서드를 호출할 때 해당 ID를 참조하면 됩니다. 예를 들어: signIn('http-email', { email: 'user@company.com' }).

Auth.js © Balázs Orbán and Team - 2025