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' })
.