728x90
728x90

Nodemailer 라이브러리

들어가며

  • Node.js 환경에서 메일을 간단하게 보낼 수 있도록 도와주는 Nodemailer 라이브러리에 대해 정리해본다.

 

Nodemailer 라이브러리

개념

  • Node.js 환경에서 이메일을 쉽게 보낼 수 있도록 도와주는 라이브러리
  • 간단한 설정으로 SMTP, OAuth2 등을 활용한 이메일 전송을 할 수 있다.
  • 텍스트와 HTML 형식의 이메일, 첨부 파일 전송 등 다양한 기능을 제공한다.
  • 무료로 사용 가능하다.
  • 오픈 소스로 관리되고 있다.

 

주요 특징

  • SMTP, OAuth2, AWS SES, SendGrid 등 다양한 이메일 서비스 지원
  • 이메일 본문을 일반 텍스트 또는 HTML 형식으로 작성 가능
  • 이미지, 문서 등 파일 첨부 가능
  • 기본 인증 외에도 OAuth2를 지원하여 보안성 강화
  • 이모티콘이나 다양한 언어의 문자를 포함한 이메일 작성 가능

 

설치하기

$ npm install nodemailer    # yarn add nodemailer

 

  • 타입스크립트(TypeScript)를 사용할 경우, 다음과 같이 타입 관련 모듈도 함께 설치해준다.
$ npm install @types/nodemailer  # yarn add @types/nodemailer

 

@@types/@로 시작하는 패키지는 타입스크립트에서 사용하는 타입 정의 파일을 제공하는 패키지이다. 이 패키지는 자바스크립트 라이브러리를 타입스크립트에서 사용할 때, 해당 라이브러리의 함수, 클래스, 속성 등의 타입을 명시적으로 정의하며, 타입스크립트의 타입 검사 IDE의 자동 완성 기능을 지원하도록 돕는다.

 

사용 방법

  • 풀스택 프레임워크Next.js(v14)타입스크립트(TypeScript)를 이용하여 기능을 구현하는 방법을 정리해본다.
  • 가장 기본적인 지메일(Gmail)을 이용해본다.

 

앱 비밀번호 생성하기

  • 이메일 발신자나의 이메일 계정을 선택해줘야 한다.
  • 나의 이메일 계정의 이메일 발송 권한을 얻기 위해서는 이메일 계정 아이디비밀번호가 필요하다.
    • 이때, 비밀번호를 앱 비밀번호(가상 비밀번호)로 설정할 수 있다.
  • 아래의 사이트에서 앱 비밀번호를 생성해주고, 그 값을 복사한다.
 

로그인 - Google 계정

이메일 또는 휴대전화

accounts.google.com

 

로그인을 하고 앱 비밀번호를 생성한 후의 모습

 

  • 복사한 앱 비밀번호를 @/.env.local@ 파일 안에 넣어준다.

 

/.env.local
  • @.env.local@ 파일안의 내용은 개발 환경
NEXT_PUBLIC_NODEMAILER_GOOGLE_ID="계정ID@gmail.com"
NEXT_PUBLIC_NODEMAILER_APP_PASSWORD="앱_비밀번호"

 

 

API 엔드 포인트 정의하기

  • @/pages/api@ 폴더 안에 @send-mail.ts@ 파일을 생성한다.
  • @/pages/api@ 폴더 안의 파일들
    • @/pages/api@에 있는 파일은 브라우저가 아닌 서버에서만 실행된다.
    • Next.js는 @/pages/api@ 폴더 안에 있는 파일을 자동으로 API 엔드포인트(Endpoint)로 만든다.
      • @/pages/api/파일명.ts@을 생성할 경우, @/api/파일명@ 엔드포인트 API 통신을 진행할 수 있다.
    • 이 폴더의 코드에서는 브라우저에서 사용할 수 없는 Node.js 모듈(@nodemailer@, @fs@, @crypto@ 등)을 자유롭게 사용할 수 있다.
    • Next.js는 @/pages/api@의 파일을 각각 서버리스 함수(Serverless Function)로 처리하므로 클라우드 서비스(Vercel 등)에 쉽게 배포할 수 있다.

 

/pages/api/send-mail.ts
import { NextApiRequest, NextApiResponse } from 'next';
import nodemailer from 'nodemailer';

// NodeMailer를 이용하여 이메일 보내기
const sendEmailWithNodeMailer = async ({
  title,
  email,
  content,
}: {
  title: string;
  email: string;
  content: string;
}) => {
  const transporter = nodemailer.createTransport({
    service: 'gmail', // 사용하는 이메일 서비스
    auth: {
      user: process.env.NEXT_PUBLIC_NODEMAILER_GOOGLE_ID, // 발신자 이메일
      pass: process.env.NEXT_PUBLIC_NODEMAILER_APP_PASSWORD, // 앱 비밀번호
    },
  });

  const mailOptions = {
    from: process.env.NEXT_PUBLIC_NODEMAILER_GOOGLE_ID, // 보내는 사람
    to: process.env.NEXT_PUBLIC_NODEMAILER_GOOGLE_ID, // 받는 사람
    subject: title, // 이메일 제목
    // text: 텍스트_형태의_메시지,
    html: `
      <p><h2>Hello <b>starrykss</b>,</h2></p>
      <p>You got a new message from <b>${email}</b>:</p>
      <p style="padding: 12px; border-left: 4px solid green; font-style: italic; background-color: rgba(222, 222, 222, 0.2);">
        <b style="font-size: 1.5rem;">${title}</b> <br />
        ${content}
      </p>
      <p>Best wishes,<br><b>${process.env.NEXT_PUBLIC_NODEMAILER_GOOGLE_ID}</b></p>
    `,
  };

  try {
    const info = await transporter.sendMail(mailOptions);
    console.log('[EMAIL SENT] ' + info.response);
  } catch (error: any) {
    throw new Error('[Nodemailer error] ' + error.message);
  }
};

// 핸들러 설정
export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  if (req.method === 'POST') {
    const { title, email, content } = req.body;

    try {
      await sendEmailWithNodeMailer({ title, email, content });

      res.status(200).json({ message: 'Email sent successfully!' });
    } catch (error: any) {
      console.error('[Email sending error] ', error);
      res.status(500).json({ error: error.message });
    }
  } else {
    res.status(405).json({ error: 'Method Not Allowed!' });
  }
};

export default handler;

 

  • 핸들러 함수(Handler Function)
    •  API로 들어오는 HTTP 요청(GET, POST 등)을 처리한다.
      • 위의 예시 코드에서는 @req.method@를 확인해 POST 요청만 처리하도록 설정했다.
    • @req.body@를 통해 클라이언트가 보낸 데이터를 읽는다. (수신자 이메일, 제목, 내용 등)
    • Nodemailer를 사용해 이메일을 전송한다.
      • 보안 관련 작업(API 키 확인, 인증 등)을 서버에서 안전하게 수행한다.
    • 클라이언트가 요청한 작업의 결과를 @res.status()@와 @res.json()@으로 반환한다.

 

사용하기

/components/MyForm.tsx
  • 폼 제출 시, 이메일 발송이 되도록 구현한 예제 코드이다.
  • @fetch@ 또는 @axios@ 를 이용하여 @form@의 입력값들을 포함하여 @/api/send-email@ 엔드포인트 POST 요청을 하면, 이메일이 발송된다.
'use client';

import { toast } from 'react-hot-toast';
import { useRef } from 'react';

export const MyForm = () => {
  const formRef = useRef<HTMLFormElement>(null);

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    const form = formRef.current;
    if (!form) return;

    const formData = new FormData(form);

    // 이메일 보내기
    const values = {
      title: formData.get('title') as string,
      email: formData.get('email') as string,
      content: formData.get('content') as string,
    };

    try {
      const response = await fetch('/api/send-email', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(values),
      });

      if (!response.ok) {
        const errorData = await response.json();
        
        throw new Error(errorData.error || 'Failed to send email');
      }

      toast.success('Email Sent Successfully!');

      // 폼 내용 비우기
      form.reset();
    } catch (error: any) {
      toast.error(`Failed to Send Email! (${error.message})`);  
  };

  return (
    <form ref={formRef} onSubmit={handleSubmit}>
      <div>
        <label htmlFor="title">Title</label>
        <input id="title" name="title" type="text" required />
      </div>
      <div>
        <label htmlFor="email">Email</label>
        <input id="email" name="email" type="email" required />
      </div>
      <div>
        <label htmlFor="content">Content</label>
        <textarea id="content" name="content" required></textarea>
      </div>
      <button type="submit">Send Email</button>
    </form>
  );
}

export default MyForm;

 

공식 문서

  • Nodemailer를 더욱 더 정교하게 사용할 수 있는데, 이와 관련된 내용은 아래의 공식 문서를 참고한다.
 

Usage :: Nodemailer

Usage Setting it up Install Nodemailer from npm To send emails you need a transporter object let transporter = nodemailer.createTransport(transport[, defaults]) Where transporter is going to be an object that is able to send mail transport is the transport

www.nodemailer.com

 

참고 사이트

 

nodemailer

Easy as cake e-mail sending from your Node.js applications. Latest version: 6.9.16, last published: a month ago. Start using nodemailer in your project by running `npm i nodemailer`. There are 8591 other projects in the npm registry using nodemailer.

www.npmjs.com

 

GitHub - nodemailer/nodemailer: ✉️ Send e-mails with Node.JS – easy as cake!

✉️ Send e-mails with Node.JS – easy as cake! Contribute to nodemailer/nodemailer development by creating an account on GitHub.

github.com

 

Sign in with app passwords - Google Account Help

Important: App passwords aren’t recommended and are unnecessary in most cases. To help keep your account secure, use "Sign in with Google" to connect apps to your Google Account. An app password is a 16-digit passcode that gives a less secure app or devi

support.google.com

 

728x90
728x90