NodeMailer는 NodeJS
서버에서 쉽게 메일(Email)을 보낼 수 있는, NodeJS
전용 모듈입니다.
예를 들어 사용자가 사이트 관리자에게 문의메일을 보낸다던지, 아니면 회원 인증 관련해서(비밀번호 초기화, 계정 잠김 등...) 서버에서 사용자에게 결과를 메일로 전송해야할 때 사용하는 유용한 라이브러리입니다.
저는 TypeScript
를 활용해서 작업해보았습니다. 참고로 TypeScript
는 마이크로소프트가 직접 개발, 관리하기 때문에 VScode
에서 기본으로 지원하므로 따로 설치할 필요가 없습니다.
프로젝트 생성 파일 디렉토리 찾기
이부분은 원하는 디렉토리 안에서 진행합니다.
`cd .....`
프로젝트 폴더 생성
`mkdir Mails`
`cd Mails`
package.json
, tsconfig.json
생성
vscode
터미널 혹은 운영체제의 터미널을 활용해 프로젝트 폴더 내에서 다음을 입력해줍니다.
npm init
Press ^C at any time to quit.
package name: (mails) nodemail
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/elitebook/project/-TEST-PostBoard/NodeJS/Mails/package.json:
{
"name": "nodemail",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this OK? (yes)
package.json
{
"name": "nodemail",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"start": "npm run build:live",
"build": "tsc --project ./",
"build:live": "nodemon --exec 'ts-node' index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"dotenv": "^16.0.1",
"express": "^4.18.1",
"nodemailer": "^6.7.5"
},
"devDependencies": {
"@types/dotenv": "^8.2.0",
"@types/express": "^4.17.13",
"@types/node": "^17.0.42",
"@types/nodemailer": "^6.4.4",
"nodemon": "^2.0.16",
"ts-node": "^10.8.1"
}
}
tsc --init
Created a new tsconfig.json with:
TS
target: es2016
module: commonjs
strict: true
esModuleInterop: true
skipLibCheck: true
forceConsistentCasingInFileNames: true
tsconfig.json
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"rootDir": ".",
"outDir": "./dist",
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
express
: 말이 필요없습니다. 쉽게 API를 구성가능한 nodeJS 최고의 프레임워크입니다.dotenv
: .env
파일에 환경변수를 저장하고 가져오기 위한 모듈입니다.nodemailer
: 메일을 전송하기 위한 Node전용 모듈입니다.nodemon
: .js
스크립트 파일을 수정 시 자동으로 새로고침을 해줍니다.ts-node
: TypeScript
를 JavaScript
로 컴파일 없이 바로 실행할 수 있도록 도와줍니다.@types
:@types
붙은 모듈은 TS
로 개발 시 반드시 필요한 모듈들을 정의합니다.express
: express
를 사용하기 위해 필요한 타입들을 가진 모듈입니다.node
: .ts
파일을 실행하기 위한 node
의 타입들을 가진 모듈입니다.dotenv
: 마찬가지로 .ts
파일에서 환경변수를 사용하기위해선 받아야하는 모듈입니다.npm i express dotenv nodemailer
npm i -D nodemon ts-node @types/express @types/node @types/dotenv @types/nodemailer
디렉토리 구조는 간단합니다.
.
├── index.ts
├── package-lock.json
├── package.json
├── public
│ ├── css
│ │ └── mail.css
│ ├── js
│ │ └── mailform.js
│ └── view
│ └── mail.html
└── tsconfig.json
nodemailer를 사용하면서 구글의 새로운 정책변경으로 인한 수정할 내용이 생겼습니다. 구글에 로그인 되어있으면 https://myaccount.google.com/security 이곳에 접속해보세요.
Enable
로 바꿔야합니다.하지만 2022년 5월 30
일 정책이 변경되었습니다.
2차인증을 켜야합니다.
앱 비밀번호를 생성해야합니다.
프로젝트에 구글 계정 Password
가 필요하다면 앱 비밀번호를 통해 서비스를 이용할 수 있습니다.
앱 비밀번호를 클릭해줍니다.
첫번째 옵션은 메일을 선택하고, 기기 선택에서는 아무거나 해줘도되는데 저는 기타로 하겠습니다.
기기용 앱 비밀번호입니다. 유출되지 않도록 주의해야합니다.
프로젝트에 상용 할 환경변수를 생성해줍니다. 저는 GMAIL
로 다룰 예정이기 때문에 Google Email
과 App Password
가 필요합니다.
MAILS_EMAIL= 'youremail' // example@gmail.com
MAILS_PWD= 'your App password' // rngalendyxplfsug
정적인 파일들을 담아놓을 폴더입니다. node.js
에서 express
를 활용해 html
,css
,js
파일을 이 폴더에 접근할것입니다.
/views/mail.html
<!DOCTYPE html>
<html>
<head>
<title>메일 서버</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" src="/css/mail.css" />
<script defer type="text/javascript" src="/js/mailform.js"></script>
</head>
<body>
<main>
<header><h2>메일 보내기</h2></header>
<form name="mailForm" method="post" id="mail_form">
<input
class="input username"
id="username"
name="username"
type="text"
placeholder="userName"
/><br />
<input
class="input email"
id="email"
name="email"
type="email"
placeholder="email"
/><br />
<input
class="input subject"
id="subject"
name="subject"
type="text"
placeholder="메일 제목"
/><br />
<textarea
class="textarea message"
id="message"
name="message"
placeholder="메일 내용"
rows="5"
cols="30"
></textarea
><br />
<input type="submit" class="submit" value="메일 보내기" />
</form>
<span>
<h3>메세지 전송상태</h3>
<input
type="text"
class="status_space"
value="메일 전송 현 상태...."
readonly
/>
</span>
</main>
</body>
</html>
/js/mailform.js
Script
에는 .ts
파일은 적용이 안되기에 .js
로 작성했습니다.let mailForm = document.getElementById('mail_form');
let username = document.querySelector('.username');
let email = document.querySelector('.email');
let subject = document.querySelector('.subject');
let message = document.querySelector('.message');
let submit = document.querySelector('.submit');
let status_space = document.querySelector('.status_space');
mailForm.addEventListener('submit', (e) => {
e.preventDefault();
let formData = {
name: username.value,
email: email.value,
subject: subject.value,
message: message.value,
};
status_space.value = '메세지 보내는중....';
let xhr = new XMLHttpRequest();
//메일 작성 을 위한 Post 메소드,
//두번쨰는 url주소
xhr.open('POST', '/');
// 문자열이 json형식이므로 content-type 헤더를 application/json
xhr.setRequestHeader('content-type', 'application/json');
xhr.onload = () => {
console.log('성공여부', xhr.responseText);
//서버에서 응답한 (res.send())결과가 일치하면 input value초기화
if (xhr.responseText === 'success') {
username.value = '';
email.value = '';
subject.value = '';
message.value = '';
status_space.value = '메일이 정상적으로 전송완료';
setTimeout(() => {
status_space.value = '메일 전송 현 상태....';
}, 3000);
} else {
status_space.value = '뭔가 오류로 메세지 전송 실패';
}
};
xhr.send(JSON.stringify(formData));
});
axios
나 fetch
만 사용하면 정말 간결하게 할 수 있는걸 목격해왔었는데... xhr
을 보니 정말 가슴이 답답하고 미치는줄 알았습니다.
import nodemailer, { Transporter } from 'nodemailer';
import 'dotenv/config';
import express, { Application, Request, Response, NextFunction } from 'express';
const app: Application = express();
const port: number = Number(process.env.PORT) || 7100;
/* 미들웨어 */
app.use(express.static('public'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
/* 메일 전송 대상(Gmail) */
let transporter: Transporter = nodemailer.createTransport({
/* Gmail Host */
host: 'smtp.gmail.com',
/* Mail port */
port: 465,
/* your Mail Service Accounts */
auth: {
/* Gmail EMAIL */
user: process.env.MAILS_EMAIL,
/* Gmail PWD */
pass: process.env.MAILS_PWD,
},
secure: true,
});
메일을 전송할 때 첨부파일을 보낸다던지 아니면 개발자에게 보낸다던지 여러가지 방법이 존재합니다. 그 중 일부분을 작성하고자 합니다.
/* 일반 전송 */
const defaultServer = () => {
app.get('/', async (req: Request, res: Response) => {
res.sendFile(__dirname + '/public/view/mail.html');
});
app.post('/', async (req: Request, res: Response) => {
console.log(req.body);
try {
let { name, email, subject, message } = req.body;
const mailhtml = `
<h3>Contact Details</h3>
<ul>
<li>Name: ${name}</li>
<li>Email: ${email}</li>
</ul>
<h3>Message</h3>
<p>${message}</p>
`;
const mailOption: SendMailOptions = {
from: email, //your or my Email(발송자)
to: process.env.NODEMAIL_EMAIL, //your or my Email(수신자)
subject: subject, // title (발송 메일 제목)
text: message, // plain text (발송 메일 내용)
html: mailhtml, // HTML Content (발송 메일 HTML컨텐츠)
};
const info: SentMessageInfo = await transporter.sendMail(mailOption);
console.log('메세지 전송됨: %s', info.messageId);
console.log('프리뷰 URL: %s', nodemailer.getTestMessageUrl(info));
res.send('success');
} catch (error) {
res.send(error).redirect('/');
}
});
app.listen(port, () => {
console.log(`이 서버는 해당 포트로 연결되었습니다. ${port}`);
});
};
defaultServer();
이 부분은 나중에 작성하겠습니다.
ref: nodemailer,waystoweb,베타맨 웍샾