paint-brush
NextAuth.js, 재전송 및 반응 이메일을 사용하여 Next.js 14에서 이메일 확인을 보내는 방법~에 의해@ljaviertovar
4,398 판독값
4,398 판독값

NextAuth.js, 재전송 및 반응 이메일을 사용하여 Next.js 14에서 이메일 확인을 보내는 방법

~에 의해 L Javier Tovar12m2024/04/02
Read on Terminal Reader

너무 오래; 읽다

이 블로그의 첫 번째 부분에서 NextAuth.js(Auth.js)를 사용하여 Next.js 14에서 인증 시스템을 구현하는 방법을 탐색한 후 사용자 정보의 유효성을 확인하기 위한 다음 단계인 이메일 유효성 검사를 수행하는 것이 중요합니다. 이 프로세스는 애플리케이션 보안의 추가 단계일 뿐만 아니라 사용자와 플랫폼 간의 상호 작용이 합법적이고 안전하다는 것을 보장하는 필수 구성 요소입니다. 이 두 번째 부분에서는 이메일 보내기, Resend를 사용하여 이메일 보내기, React Email을 사용하여 매력적이고 기능적인 이메일 템플릿을 만드는 등 이메일 검증을 통합하는 데 중점을 둘 것입니다.
featured image - NextAuth.js, 재전송 및 반응 이메일을 사용하여 Next.js 14에서 이메일 확인을 보내는 방법
L Javier Tovar HackerNoon profile picture
0-item
1-item

이 블로그의 첫 번째 부분에서 NextAuth.js(Auth.js)를 사용하여 Next.js 14에서 인증 시스템을 구현하는 방법을 탐색한 후 사용자 정보의 유효성을 확인하기 위한 다음 단계인 이메일 유효성 검사를 수행하는 것이 중요합니다.


이 프로세스는 애플리케이션 보안의 추가 단계일 뿐만 아니라 사용자와 플랫폼 간의 상호 작용이 합법적이고 안전하다는 것을 보장하는 필수 구성 요소입니다.


이 두 번째 부분에서는 이메일 보내기, Resend를 사용하여 이메일 보내기, React Email을 사용하여 매력적이고 기능적인 이메일 템플릿을 만드는 등 이메일 검증을 통합하는 데 중점을 둘 것입니다.

초기 구성

프로젝트에 블로그의 첫 번째 부분에서 설명한 인증 시스템이 이미 구현되어 있는지 확인하세요. 여기에는 Next.js 14 및 NextAuth가 올바르게 구성된 것이 포함됩니다.


Next.js의 재전송 및 Ract 이메일 통합

설정

  1. 프로젝트에 필요한 종속성을 설치합니다. 이번에는 pnpm 사용하겠습니다. 원하는 패키지 관리자를 사용할 수 있습니다.


 pnpm add resend react-email @react-email/components



  • 이메일에 반응 : React와 TypeScript를 사용하여 아름다운 이메일을 만듭니다.


2. 프로젝트에 대해 다음 구조를 생성합니다.


 ... ├── emails/ │ └── verification-template.tsx ... ├── src/ │ ├── actions/ │ │ ├── email-actions.tsx │ │ └── auth-actions.tsx │ ├── app/ │ │ ... │ │ ├── (primary)/ │ │ │ ├── auth/ │ │ │ │ └── verify-email/ │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ │ ... │ ├── components/ │ │ └── auth/ │ │ ├── signin-form.tsx │ │ ├── signup-form.tsx │ │ ... │ ... │ ├── utils.ts │ ... ... ├── .env ...


React 이메일로 이메일 템플릿 만들기

React Email을 사용하면 JSX를 사용하여 이메일 템플릿을 만들 수 있으며, 이를 통해 브랜드와 관련된 매력적이고 일관된 이메일을 쉽게 만들 수 있습니다.


React 컴포넌트로 기본 이메일 템플릿을 만들어 보겠습니다. 이 경우 사용자가 이메일을 확인할 수 있도록 전송되는 템플릿을 생성합니다.


emails/verification-template.tsx :

 // Import React and necessary components from @react-email/components import * as React from 'react'; import { Body, Button, Container, Head, Hr, Html, Img, Preview, Section, Text } from '@react-email/components'; import { getBaseUrl } from '@/utils'; // Obtain the base URL using the imported function const baseUrl = getBaseUrl(); // Define the properties expected by the VerificationTemplate component interface VerificationTemplateProps { username: string; emailVerificationToken: string; } // Define the VerificationTemplate component that takes the defined properties export const VerificationTemplate = ({ username, emailVerificationToken }: VerificationTemplateProps) => ( <Html> <Head /> <Preview>Preview text that appears in the email client before opening the email.</Preview> <Body style={main}> <Container style={container}> <Img src='my-logo.png' alt='My SaaS' style={logo} /> <Text style={title}>Hi {username}!</Text> <Text style={title}>Welcome to Starter Kit for building a SaaS</Text> <Text style={paragraph}>Please verify your email, with the link below:</Text> <Section style={btnContainer}> {/* Button that takes the user to the verification link */} <Button style={button} href={`${baseUrl}/auth/verify-email?token=${emailVerificationToken}`} > Click here to verify </Button> </Section> <Hr style={hr} /> <Text style={footer}>Something in the footer.</Text> </Container> </Body> </Html> ); // Styles applied to different parts of the email for customization const main = { backgroundColor: '#020817', color: '#ffffff', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif', }; const container = { margin: '0 auto', padding: '20px 0 48px', }; ...


이 구성 요소는 스타일과 동적 콘텐츠를 포함하는 HTML 이메일 템플릿을 생성합니다.


username y emailVerificationToken 수신하도록 속성이 정의됩니다. 이러한 속성은 사용자의 이메일을 맞춤설정하고 확인 링크를 생성하는 데 사용됩니다.


템플릿을 검증하고 테스트하기 위해 React Email은 이메일 폴더 내에 생성한 템플릿을 노출하는 서버를 로컬로 실행하는 명령을 제공합니다.


  1. 서버를 실행하기 위해 package.json 에 스크립트를 만듭니다.


 { "scripts": { "dev": "email dev" } }


2. 스크립트를 실행하면 localhost 에서 서버가 실행됩니다. 생성된 모든 템플릿이 포함된 다음과 같은 화면이 표시됩니다.


로컬 반응 이메일


우리의 경우에는 템플릿이 하나만 있습니다. 아래에서 볼 수 있듯이 사용자에게 전송될 이메일의 미리보기가 있습니다.


이메일 인증


재전송으로 이메일 보내기

  1. 만들기 계정 재전송 .
  2. 새로 만들기 API 키 .
  3. .env 파일에 API KEY 추가합니다.


 ... # resend RESEND_API_KEY="re_jYiFaXXXXXXXXXXXXXXXXXXX"


4. 이메일 전송 기능을 생성하기 위해 api/ 폴더 내에 엔드포인트를 생성하고 http 요청을 할 수 있지만, 이 경우 서버 작업 잠재력을 활용하여 수행하겠습니다.


actions/email-actions.ts :

 'use server' import React from 'react' import { Resend } from 'resend' // Creates an instance of Resend using the API KEY const resend = new Resend(process.env.RESEND_API_KEY) // Defines the data structure for an email. interface Email { to: string[] // An array of email addresses to which to send the email. subject: string // The subject of the email. react: React.ReactElement // The body of the email as a React element. } export const sendEmail = async (payload: Email) => { const { error } = await resend.emails.send({ from: 'My SaaS <[email protected]>', // Defines the sender's address. ...payload, // Expands the contents of 'payload' to include 'to', 'subject', and 'react'. }) if (error) { console.error('Error sending email', error) return null } console.log('Email sent successfully') return true }


참고: 무료 개발에서 테스트하려면 “[email protected]” 이메일을 발신자로 사용해야 합니다. 그렇지 않으면 사용자 정의 도메인을 추가해야 합니다.


5. 신규 사용자 등록 시 이메일을 발송합니다.


actions/auth-actions.ts :

 ... import { sendEmail } from './email-actions' import VerificationTemplate from '../../emails/verification-template' // Import a utility function to generate a secure token. import { generateSecureToken } from '@/utils' export async function registerUser(user: Partial<User>) { try { // Creates a new user in the database with the provided data. // Passwords are hashed using bcrypt for security. const createdUser = await prisma.user.create({ data: { ...user, password: await bcrypt.hash(user.password as string, 10), } as User, }) // Generates a secure token to be used for email verification. const emailVerificationToken = generateSecureToken() // Updates the newly created user with the email verification token. await prisma.user.update({ where: { id: createdUser.id, }, data: { emailVerificationToken, }, }) // Sends a verification email to the new user using the sendEmail function. await sendEmail({ to: ['your Resend registered email', createdUser.email], subject: 'Verify your email address', react: React.createElement(VerificationTemplate, { username: createdUser.username, emailVerificationToken }), }) return createdUser } catch (error) { console.log(error) if (error instanceof Prisma.PrismaClientKnownRequestError) { if (error.code === 'P2002') { // Returns a custom error message if the email already exists in the database. return { error: 'Email already exists.' } } } return { error: 'An unexpected error occurred.' } } }


사용자가 생성되고 확인 토큰이 생성되면 함수는 새 사용자에게 이메일을 보냅니다.


이 이메일은 VerificationTemplate React 구성 요소를 사용하여 구성되었으며 사용자 이름과 확인 토큰으로 개인화되었습니다. 이 단계는 사용자의 이메일 주소가 유효하고 사용자가 제어하는지 확인하는 데 중요합니다.


성공적으로 가입했습니다


토큰 검증 페이지

이메일이 사용자에게 전송되면 해당 사이트로 다시 연결되는 링크가 포함됩니다. 이메일을 검증하려면 페이지를 생성해야 합니다.


(primary)/auth/verify-email/page.tsx :

 /* All imports */ // Defines the prop types for the VerifyEmailPage component. interface VerifyEmailPageProps { searchParams: { [key: string]: string | string[] | undefined } } export default async function VerifyEmailPage({ searchParams }: VerifyEmailPageProps) { let message = 'Verifying email...' let verified = false if (searchParams.token) { // Checks if a verification token is provided in the URL. // Attempts to find a user in the database with the provided email verification token. const user = await prisma.user.findUnique({ where: { emailVerificationToken: searchParams.token as string, }, }) // Conditionally updates the message and verified status based on the user lookup. if (!user) { message = 'User not found. Check your email for the verification link.' } else { // If the user is found, updates the user record to mark the email as verified. await prisma.user.update({ where: { emailVerificationToken: searchParams.token as string, }, data: { emailVerified: true, emailVerificationToken: null, // Clears the verification token. }, }) message = `Email verified! ${user.email}` verified = true // Sets the verified status to true. } } else { // Updates the message if no verification token is found. message = 'No email verification token found. Check your email.' } return ( <div className='grid place-content-center py-40'> <Card className='max-w-sm text-center'> <CardHeader> <CardTitle>Email Verification</CardTitle> </CardHeader> <CardContent> <div className='w-full grid place-content-center py-4'> {verified ? <EmailCheckIcon size={56} /> : <EmailWarningIcon size={56} />} </div> <p className='text-lg text-muted-foreground' style={{ textWrap: 'balance' }}> {message} </p> </CardContent> <CardFooter> {verified && ( // Displays a sign-in link if the email is successfully verified. <Link href={'/auth/signin'} className='bg-primary text-white text-sm font-medium hover:bg-primary/90 h-10 px-4 py-2 rounded-lg w-full text-center'> Sign in </Link> )} </CardFooter> </Card> </div> ) }


사용자의 이메일을 성공적으로 검증하면 다음 메시지가 표시됩니다.


토큰을 검증하는 페이지


이제 사용자가 로그인을 원하지만 아직 이메일을 확인하지 않은 경우에 대한 마지막 검증을 구현하겠습니다.


components/auth/sigin-form.tsx :

 ... async function onSubmit(values: InputType) { try { setIsLoading(true) const response = await signIn('credentials', { redirect: false, email: values.email, password: values.password, }) if (!response?.ok) { // if the email is not verified we will show a message to the user. if (response?.error === 'EmailNotVerified') { toast({ title: 'Please, verify your email first.', variant: 'warning', }) return } toast({ title: 'Something went wrong!', description: response?.error, variant: 'destructive', }) return } toast({ title: 'Welcome back! ', description: 'Redirecting you to your dashboard!', }) router.push(callbackUrl ? callbackUrl : '/') } catch (error) { console.log({ error }) toast({ title: 'Something went wrong!', description: "We couldn't create your account. Please try again later!", variant: 'destructive', }) } finally { setIsLoading(false) } } ... 


이메일 인증


그게 다야! 🎉


사용자는 자신의 이메일을 확인하고 애플리케이션에서 등록을 완료할 수 있습니다.


🧑‍💻 여기에 레포

결론

우리는 React Email과 Resend를 사용하여 이메일을 만들고 보내는 방법을 이미 알고 있습니다. 이 프로세스를 통해 React에 대한 지식을 활용하여 익숙하고 생산적인 작업 흐름을 유지하면서 효율적으로 이메일을 디자인할 수 있습니다.


다양한 구성 요소와 속성을 실험하여 프로젝트 요구 사항에 완벽하게 맞는 이메일을 만들 수 있습니다.


저자와 연결하고 싶나요?


𝕏 에서 전 세계 친구들과 소통하는 것을 좋아합니다.


여기에도 게시됨