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)을 이용해본다.
앱 비밀번호 생성하기
- 이메일 발신자는 나의 이메일 계정을 선택해줘야 한다.
- 나의 이메일 계정의 이메일 발송 권한을 얻기 위해서는 이메일 계정 아이디와 비밀번호가 필요하다.
- 이때, 비밀번호를 앱 비밀번호(가상 비밀번호)로 설정할 수 있다.
- 아래의 사이트에서 앱 비밀번호를 생성해주고, 그 값을 복사한다.
- 앱 비밀번호를 생성하기 위해서는 로그인이 필요하다.
- https://myaccount.google.com/apppasswords
- 복사한 앱 비밀번호를 @/.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()@으로 반환한다.
- API로 들어오는 HTTP 요청(GET, POST 등)을 처리한다.
사용하기
/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를 더욱 더 정교하게 사용할 수 있는데, 이와 관련된 내용은 아래의 공식 문서를 참고한다.
참고 사이트
728x90
728x90
'Programming > Node.js' 카테고리의 다른 글
[Node.js] 모듈 설치 시 의존성 문제 해결하기 (npm-check-updates) (1) | 2023.11.27 |
---|---|
[Node.js] PostgreSQL 설치 및 사용해보기 (0) | 2023.11.17 |
[Node.js] EJS(Embedded JavaScript) (0) | 2023.11.09 |
[Node.js] morgan 패키지 (0) | 2023.11.09 |
[Node.js] body-parser 패키지 (0) | 2023.11.09 |
[Node.js] 노드몬(nodemon) 패키지 (0) | 2023.11.08 |
[Node.js] Express.js (0) | 2023.11.08 |
[Node.js] URL QR 코드 생성기 만들기 (0) | 2023.11.07 |