본문으로 바로가기

NestJS, AWS 메일서버 환경에서 mailer와 ejs를 사용하여 메일 발송을 위해 작업을 하였고,

너무 정보가 많이 없어서 까먹으면 고생할것 같아서 작성합니다.

 

패키지는 다음과 같이 추가하였습니다. (mailer, ejs, nodemailer)

npm install @nestjs-modules/mailer ejs nodemailer --save

 

nest-cli.json

{
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {	// ejs 사용시 필수 추가!
    "assets": [{"include": "**/*.ejs"}],
    "watchAssets": true
  }
}

초반에 작업할 떄 ejs 파일이 dist 폴더에 들어가지 않아서 불러오지 못하는 문제에 직면했습니다. 허허..

찾아보니 nest-cli를 설정해주어야 컴파일시 ejs도 같이 들어가더라구요.

 

email/email.module.ts

import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from '@nestjs/config'
import { MailerModule } from '@nestjs-modules/mailer'
import { EjsAdapter } from '@nestjs-modules/mailer/dist/adapters/ejs.adapter'
import * as path from 'path'
import * as AWS from 'aws-sdk'

import { EmailService } from "./email.service";

@Module({
  imports: [
    MailerModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        transport: {
          SES: new AWS.SES({
            region: config.get('AWS_REGION'),
            accessKeyId: config.get('AWS_ACCESS_KEY_ID'),
            secretAccessKey: config.get('AWS_SECRET_ACCESS_KEY'),
          }),
          host: config.get('AWS_SES_SMTP_ENDPOINT'),
          port: config.get('AWS_SES_PORT'),
          secure: false,
          debug: true,
        },
        default: {
          from: '"19-97" <no-reply@19-97.com>',
        },
        template: {
          dir: path.join(__dirname, '/templates/'),
          adapter: new EjsAdapter(),
          options: {
            strict: true,
          },
        },
      }),
    }),
  ],
  providers: [EmailService],
  exports: [EmailService],
})
export class EmailModule {}

처음에는 transport 덕분에 애먹었습니다..

다른 분들은 host, user, pass 라는 parameter로 처리를 하시던데, 저는 그게 안되더라구요..

플젝중이라 빠르게 처리를 해야되는 부분이라 선배님의 과거의 작업물(nuxt)를 참고해서 수정하였습니다.

 

adapter는 pug나 handlerbars로도 가능하다고 많이 적혀있지만,

저는 추가적으로 패키지 다운로드를 하지 않으려고 mailer에 있는 EjsAdapter를 사용했습니다.

 

email/email.service.ts

import { MailerService } from "@nestjs-modules/mailer";
import { Injectable } from "@nestjs/common";

@Injectable()
export class EmailService {
  constructor(private readonly mailerService: MailerService) {}

  async _send({
    toEmails,
    subject,
    templateName,
    context,
  }): Promise<boolean> {
    let isSendAllSuccess = true
    for (let toEmail of toEmails) {
      await this.mailerService.sendMail({
        to: toEmail,
        from: '"19-97" <no-reply@19-97.com>',
        subject,
        template: `./${templateName}`,
        context,
      })
        .then(info => {
          console.log(`"${toEmail}" Email Sending Complete!! => ${info.response}`)
        })
        .catch(err => {
          console.log(`"${toEmail}" Email Sending ERORR!! => ${err}`)
          isSendAllSuccess = false
        })
    }

    return isSendAllSuccess
  }
}

해당 이메일은 개별적으로 보내는 용도로 제작이 되었지만,

누구누구에게 보냈는지 수신자가 알아도 상관없으시다 하시면 to: toEmails.join(', ') 형태로 호출하면 됩니다!

 

(default에 from을 설정해놨어서 from이 빠져도 된다고 생각했는데, 자꾸 처음보는 친구를 보여주면서 string 타입이어야된다고 뜨더니 저 친구였었던건 비밀입니다..)

 

ejs의 prameter (<%=hello%> 형태)의 값은 context를 통해서 전달됩니다.

 

email/template/sign-up.ejs 의 일부분

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>회원가입을 위한 인증 메일입니다.</title>
</head>
<body>
<div>
  <div 
    class="container" 
    style="
      max-width: 600px; 
      height: 860px;
    "
  >
    <div 
      class="container-middle" 
      style="width: 100%;
      padding: 60px 0px 40px 0px;"
    >
      <h2 
        style="font-size: 35px; 
          font-weight: lighter; 
          margin: 0 0 0 0;"
      >
        회원가입을 위한 <br/> 
        <b>인증메일</b> 입니다.
      </h2>

      <p 
        style="margin-bottom: 20px;  
          color: #3a3939;"> 
        메일 인증하기 버튼을 클릭하면 회원가입이 완료됩니다.
      </p>

      <a href="<%=urlLink%>"
        style="text-decoration: none;
          color: black;
          display: block;
          width: 295px;
          font-size: 20px;
          padding: 15px 0;
          background-color: #ffe400;
          text-align: center;
          margin: 40px 0 0 0;
          font-weight: 900;
          border-radius: 20px;"
      >
        메일 인증하기
      </a>
    </div>
  </div>
</div> 
</body>
</html>

자꾸 파라미터 값이 전달되지 않아서 찾아보니  앞에 locals.params 형태로 사용하라는 stackoverflow 형님들의 글을 보고 적용하니

메일이 제대로 발송되는것을 보면서 행복했습니다 ㅠㅠㅠ

 

반응형