Nestjs EjsAdaptor email template ๋ง๋ค๊ธฐ
ํ์ฌ์์ ์ธ์ฆ ๋ก์ง์ ๊ตฌํํ๋ ์ค, ํ์๊ฐ์ ์ด๋ฉ์ผ confirm ํ์ธ ๋ฉ์ผ๊ณผ ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ํ์ธ ๋ฉ์ผ ๋ฑ ์ฌ๋ฌ๊ฐ์ง ๋ฉ์ผ๋ค์ ๋ณด๋ด์ผ ํด์ EjsAdapter + nestjs mailer module ์ ์จ์ ํ ํ๋ฆฟ์ ๋ง๋ค์ด ๋๊ณ mail service ํจ์๋ฅผ ์ฌ์ฌ์ฉํ์๋ค.
๊ธฐ์กด ์ฝ๋
import { MailerModule } from '@nestjs-modules/mailer'; import { EjsAdapter } from '@nestjs-modules/mailer/dist/adapters/ejs.adapter'; import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; @Module({ imports: [ MailerModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => ({ transport: { host: 'smtp.gmail.com', port: 587, secure: false, auth: { user: configService.get<string>('SMTP_AUTH_USER'), pass: configService.get<string>('SMTP_AUTH_PW'), }, }, defaults: { from: process.env.SUPPORT_EMAIL, }, template: { dir: `${path.resolve(__dirname, '../../templates')}`, adapter: new EjsAdapter(), options: { strict: true, }, }, }), }), ], }) export class MailModule {}
๋ฆฌํฉํ ๋ง ์ )
์ด๋ ๊ฒ mail Module ์ ๋ง๋ค์ด๋๊ณ , ์ด๋ฉ์ผ์ ๋ณด๋ด์ผ ํ๋ ์๋น์ค ํจ์์์ ์๋์ฒ๋ผ mailerService.sendMail ์ ํธ์ถํ์๋ค. (mailerService ๋ nestjs mailer ๋ชจ๋์์ ์ ๊ณต)
await this.mailerService .sendMail({ to: email, from: this.configService.get<string>('SMTP_AUTH_USER'), subject: 'Sign Up', text: 'welcome', html: ` <div style="text-align: center; padding: 20px"> <h3>Email Verification</h3> <p> Please click the button below to confirm your email and finish setting up your account. This link is valid for <span style="color: red; font-weight: bold">24 hours</span></p> <a role="button" style=" border: 1px solid; border-radius: 17px; padding: 10px; color: black; text-decoration: none; display: inline-block; margin-bottom: 15px; " href="${signUpLink}" > Confirm </a> </div> `, })
์ดํ์ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ์ปจํ ์ด๋ฉ์ผ ์์ ์ ํ๋ ค๋ค๋ณด๋ ์ค๋ณต ์ฝ๋๊ฐ ๋ฐ์ํ ๊ฒ ๊ฐ์
๋ฆฌํฉํ ๋งํด์ sendMail ํจ์๋ก ๋ฐ๊ฟ์ ์์ผ๋ก ๋ฉ์ผ๋ค์ด ์ถ๊ฐ๋์ด๋ ์ฌ์ฌ์ฉํ ์ ์๋๋ก ํ๋ค.
์ต์ข ์ฝ๋
const signUplogic = async (signUpRequestDto: SignUpRequestDto): Promise<void> => { // do business logic... await this.mailerService .sendMail({ to: email, from: this.configService.get<string>('SMTP_AUTH_USER'), subject: 'Sign Up', template: 'sign-up-confirm' }) } const resetPassword = async (resetPasswordDto: ResetPasswordDto): Promise<void> => { // do business logic.. await this.mailerService .sendMail({ to: email, from: this.configService.get<string>('SMTP_AUTH_USER'), subject: 'Reset your password', template: 'reset-password-confirm' }) } // create root/templates/sign-up-confirm.ejs // create root/templates/reset-password-confirm.ejs
์ค์ ๋ฏ์ด๋ณด๊ธฐ
// mailModule template: { dir: `${path.resolve(__dirname, '../../templates')}`, adapter: new EjsAdapter(), options: { strict: true, }, },
__dirname ์ด๋ nestjs ๋ typescript ๋ก ์์ฑ๋ ์ฝ๋๋ฅผ ํ ๋ฒ compile ํด javascript ๋ก ๋ณํํ๋ค์, dist ํด๋ ์์ ์๋ Main.js ๋ฅผ ์คํํ๋ค. __dirname ์ ์คํ ์ ํ์ฌ ํ์ผ๋ช ๊ณผ ํ์ผ ๊ฒฝ๋ก๋ฅผ ์๋ฏธํ๋ค. file ๋ช ์ ์ ์ธํ ์ ๋ ๊ฒฝ๋ก์ด๋ค. ๊ทธ๋์ ์คํ ๋น์์๋ src ๊ฐ ์๋๋ผ dist ์์ ์๋ dist/templates ๋ฅผ ์ฐพ์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ src/templates ๋ฅผ dist ๋ก ์ฎ๊ฒจ์ฃผ์ด์ผ ํ๋ค.
nest-cli.json ์๋ compiler option ์ ์ค ์ ์๋ค.
"compilerOptions": { "assets": ["**/*.ejs"], "watchAssets": true },
nest-cli.json ์ ์ ์ฝ๋๋ฅผ ์ถ๊ฐํ๊ณ , ๋ก์ปฌ ์๋ฒ๋ฅผ ํ ๋ฒ ๊ป๋ค๊ฐ ๋ค์ ์์ํ๋ฉด dist ํด๋์ templates ํด๋๊ฐ ์ ์์ฑ๋จ์ ํ์ธํ ์ ์๋ค.
์ ์์ฑ๋ dist
Q. yarn start:local ์ ํ๋๋ฐ __dirname ์ด dist/src/mail/templates ๋ก ๋์ด ์์ด ๋ชป ์ฐพ๊ณ ์๋ค. ๋ฉ์ผ ํ ํ๋ฆฟ๋ค์ dist/templates ์ ์์นํ๋ค. ์ด๋ป๊ฒ ๋ฐ๊ฟ ์ ์์๊น?
์ ์ฝ๋์์๋
// MailModule template: { dir: `${path.resolve(__dirname, '../../templates')}`, adapter: new EjsAdapter(), options: { strict: true, }, },
์ด๋ ๊ฒ ๋์ด ์์ง๋ง ์๋๋ dir: ${__dirname}/templates
๋ก ๋์ด ์์๋ค.
์ด๋ ๊ฒ ํ์ ๋ __dirname ์ด dist/src/mail/templates ๋ก ๋๋ ๋ฌธ์ ๊ฐ ์์ด์ path module ์ resolve ๋ฉ์๋๋ฅผ ์จ์ ํด๊ฒฐํ์๋ค.
Q. ejs ํ์ผ์ ๋ณ์๋ฅผ ์ด๋ป๊ฒ ๋๊ธฐ๋? mailer module ์ context ์ต์ ์ ์ฌ์ฉํ๋ฉด ๋๋ค. template options ์ strict ๋ชจ๋๋ฅผ ๊บผ์ฃผ๊ฑฐ๋, ์ผ์ผ ํ๋ค๋ฉด ๋ณ์ ์์ locals ๋ฅผ ๋ถ์ฌ์ค๋ค.
template: { dir: `${__dirname}/templates`, adapter: new EjsAdapter(), options: { strict: true, }, },
href="<%=locals.signUpLink}"%>