https://github.com/seomimi/nodemailer
이 글은 node와 express를 이용한 노드 서버 생성
에 대한 선수 지식이 있어야 원활한 이해가 가능합니다.
Nodemailer는 이메일을 보낼 수 있는 Node.js 애플리케이션용 모듈로, EmailEngine에 등록된 이메일 계정을 사용하여 이메일을 수신하고 이메일을 보낼 수 있습니다.
더 자세한 기능 및 특징은 https://nodemailer.com/about/
를 참고해 주세요.
주요 개념
고객이 회사에 어떠한 문의사항을 보낼 때, outlook이나 외부 메일 시스템으로 연결 없이, 회사 홈페이지에서 바로 보낼 수 있는 환경을 구축하기 위해 사용했습니다.
제가 실제 업무에서 만든 형식은 아니지만, 블로그 글 업로드를 위해 간단히 만들었습니다.
관련 코드는 깃에서 확인해 주세요.
Node.js + express 사용하여 간단하게 로컬에 백서버를 만들었습니다.
이 또한 관련 코드는 깃에서 확인해 주세요.
(서버를 만들지 않고 AWS lambda를 이용하여 서버리스로 메일 보내기도 가능합니다... 다음 포스팅으로 해볼까 싶기도...ㅎㅎ)
> npm i nodemailer
let transporter = nodemailer.createTransport(options[, defaults])
메일을 보내기 위한 송신객체를 createTransport를 사용하여 생성합니다.
저는 gmail을 통해 메일을 보낼 것이므로 구글 계정 설정에서 앱 비밀번호를 발급받아야 합니다.
저는 앱선택 : 기타 -> 이름 : nodemailer
로 설정하여 생성했습니다.
16자리의 앱 비밀번호가 생성되는데 한 번 발급받으면 다시 알 수 없으므로 어딘가에 잘 기록해두세요.
nodemailer.createTransport({
host: "smtp.gmail.com",
port: 587,
secure: false,//port 587의 경우, secure가 false로 유지
//secure가 false라고 해서 암호화된 연결을 사용하지 않는다는 의미가 아닙니다.
auth: {
user: "자신의 구글계정@gmail.com",
pass: "16자리 앱 비밀번호",
},
});
전에는 node서버에서 구글 메일에 접속하기 위해 구글 2단계 인증을 해제해서 써야했지만, 이제는 앱 비밀번호를 발급받아 사용하므로 보안문제가 해결되었습니다.
transporter.sendMail(data[, callback])
// back/routes/mailSender.js
let mailOptions = {
from: "xxx@gmail.com", //송신할 이메일
to: "xxx@gmail.com", //수신할 이메일
subject: "메일 제목",
html: "메일 내용",
attachments: "첨부파일",
};
transporter.sendMail(mailOptions)
callback 인수가 설정되지 않은 경우 메서드는 Promise 객체를 반환합니다.
attachments에 첨부파일을 넣어 보낼 수 있습니다. (배열로 여러 개의 첨부파일을 보내기 가능)
attachments의 형식 예시는 https://nodemailer.com/message/attachments/
에서 볼 수 있습니다.
저는 첨부파일의 형식을 data uri로 변경하여 보냅니다.
(데이터가 base-64로 인코딩 되면서 크기가 1/3정도 증가하므로 주의)
// front/components/MailForm.tsx
const onSelectFile = useCallback((e) => {
if (fileCheck(e.target.files[0].type)) {
let reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
reader.onloadend = () => {
const base64 = reader.result;
if (base64) {
let base64Sub = base64.toString();
setFileInfo(base64Sub);
}
};
} else {
alert('pdf 파일만 업로드 가능합니다.');
}
}, []);
https://github.com/seomimi/nodemailer
// front/components/MailForm.tsx
const onSubmit = useCallback(
(e) => {
e.preventDefault();
if (email && title && message && fileInfo) {
const payload = { email: email, title: title, message: message, file: fileInfo };
axios
.post('http://localhost:3005/back/mail', payload)
.then((res) => console.log(res))
.catch((err) => console.error(err));
}
},
[email, title, message, fileInfo]
);
위 이미지처럼 내용을 작성해서 보내면, back에서 req.body로 받습니다.
front에서 받은 메일을 최종 수신할 메일로 보냅니다.
// back/routes/mailSender.js
// back/routes/mail.js
const express = require('express');
const router = express.Router();
router.post('/', async (req, res, next) => {
try {
let transporter = nodemailer.createTransport({
port: 587,
host: 'smtp.gmail.com',
auth: {
user: 'xxx@gmail.com', //송신할 이메일
pass: '16자리 앱 비밀번호',
},
});
const { email, title, message, file } = req.body;
let mailOptions = {
from: 'xxx@gmail.com', //송신할 이메일
to: 'xxx@gmail.com', //수신할 이메일
subject: 'nodemailer test',
html: `
<div>
<h2>Message Details</h2>
<div class="email" style="font-size: 1.1em;">Email : ${email}</div>
<div class="phone" style="font-size: 1.1em;">Title : ${title}</div>
<div class="message" style="font-size: 1.1em;">message : </div>
<pre class="message" style="font-size: 1.2em;">${message}</pre>
</div>
`,
attachments: [{ path: file }],
};
await transporter
.sendMail(mailOptions)
.then(() => res.status(200).send('저장 및 발송 성공'))
.catch(() => res.status(500).send('에러'));
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
송신이 완료되면 보낸 메일에서 확인 할 수 있습니다.
nodemailer로 인해 생긴 에러 사항은 아니고, 백서버에 파일 한계 용량을 늘리지 않아서 axios 에러가 떴었다.
express 서버에 아무 설정을 추가하지 않으면 기본값은 100kb 입니다.
// back/app.js
app.use(express.json({ limit: '25mb' }));
app.use(express.urlencoded({ limit: '25mb', extended: true }));