1、前言
本文章记录自己学习
Nest
的过程,适于前端及对后端没有基础但对Nest
感兴趣的同学,如有错误,欢迎各位大佬指正
2、Nest
成长足迹系列:
- 篇幅一: Nest介绍、swagger的使用
- 篇幅二:TypeORM操作数据库、Pipe校验参数
- 篇幅三:用户登录颁发jwt
- 篇幅四:使用nodemailer发送html/ejs文件模版的邮箱验证码(本篇)
3、正文
3.1、使用nodemailer
- 安装
nodemailer
sh
npm install nodemailer --save
3.2、qq邮箱开启发邮件服务
- 想要使用qq邮箱的发送邮件服务,需要开启POP3/SMTP/IMAP功能,在qq邮箱的邮箱设置中找到账号tab
- 往下滑可以看到:(我这个是已开启的状态,你未开启的话需要自己开启)
- 开启之后,可以获取授权码,点击之后会跳到验证页面,会需要发送一条短信,验证通过后即可获取到授权码
email.service.ts
ts
import { Injectable } from '@nestjs/common';
import { createTransport, Transporter } from 'nodemailer';
@Injectable()
export class EmailService {
transporter: Transporter;
constructor() {
this.transporter = createTransport({
host: 'smtp.qq.com', // smtp服务的域名
port: 587, // smtp服务的端口
secure: false,
auth: {
user: process.env.EMAIL_USER, // 你的邮箱地址
pass: process.env.EMAIL_PASS // 你的授权码
}
});
}
async sendMail({ to, subject, html }) {
await this.transporter.sendMail({
from: {
name: 'xxx系统',
address: process.env.EMAIL_USER // 你的邮箱地址
},
to,
subject,
html
});
}
}
email.controller.ts
- 在这个文件中有两个路由写到了一起,只是url不一致
- 在
Nest
项目中HTML
文件通常不会被自动打包到dist
文件夹中,因为Nest.js
主要用于构建后端应用程序,而不是前端应用程序。dist
文件夹通常包含编译后的服务器代码和依赖项,而不包括前端资源。 - 所以,我们需要将
html
/ejs
的模版文件放到public
文件夹中
ts
import { Controller, Get, Inject, Query, Request } from '@nestjs/common';
import * as path from 'path';
import * as fs from 'fs';
import * as ejs from 'ejs';
import { EmailService } from '../services/email.service';
import { RedisService } from '../services/redis.service';
import {
REGISTER_CAPTCHA,
UPDATE_PASSWORD_CAPTCHA
} from '@/common/constant/common-constants';
import { BusinessException } from '@/common/exceptions/business.exception';
@Controller('captcha')
export class EmailController {
@Inject(EmailService)
private emailService: EmailService;
@Inject(RedisService)
private redisService: RedisService;
@Get(['register', 'update_password'])
async captcha(@Query('address') address: string, @Request() req) {
// 生成一个长度为 6 的随机字符串
const code: string = Math.random().toString().slice(2, 8);
const url: string = req.route.path;
const keyMap = {
'/api/captcha/register': `${REGISTER_CAPTCHA}_${address}`,
'/api/captcha/update_password': `${UPDATE_PASSWORD_CAPTCHA}_${address}`
};
const subjectMap = {
'/api/captcha/register': '注册验证码',
'/api/captcha/update_password': '修改密码验证码'
};
// 读取 HTML 模板文件
try {
/**
* 在 Nest.js 项目中,HTML 文件通常不会被自动打包到 dist 文件夹中,因为 Nest.* js主要用于构建后端应用程序,而不是前端应用程序。dist 文件夹通常包含编译后的服务* 器代码和依赖项,而不包括前端资源。
*/
// ejs || html
const htmlPath: string = path.join(__dirname, '../../public/email.html');
const emailTemplate = fs.readFileSync(htmlPath, 'utf-8');
// 使用 EJS 替换验证码
const validity: number = 5; // 有效期5min
const emailConfig = {
code,
validity,
name: '晚风予星'
};
const emailHtml = ejs.render(emailTemplate, emailConfig);
await this.redisService.set(keyMap[url], code, validity * 60);
await this.emailService.sendMail({
to: address,
subject: subjectMap[url],
html: emailHtml
});
return '发送成功';
} catch (e) {
throw new BusinessException('读取文件失败!');
}
}
}
3.3、使用html模版
- 而想要使用
html
/ejs
的模版文件发送邮件验证码,需要安装ejs
包
sh
yarn add ejs -D
- 在添加
html
文件以及写好html
后你会发现文件报错了,这表明ESLint
不知道如何解析这种文件扩展名
html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="description" content="email code" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>验证码邮件</title>
</head>
<!--邮箱验证码模板-->
<body>
<div style="background-color: #ececec; padding: 35px">
<table
cellpadding="0"
style="
width: 800px;
height: 100%;
margin: 0px auto;
text-align: left;
position: relative;
border-radius: 5px;
font-size: 14px;
font-family: 微软雅黑, 黑体;
line-height: 1.5;
box-shadow: rgb(153, 153, 153) 0px 0px 5px;
border-collapse: collapse;
background: #fff;
background-position: initial initial;
background-repeat: initial initial;
"
>
<tbody>
<tr>
<th
style="
height: 25px;
line-height: 25px;
padding: 15px 35px;
border-bottom: 1px solid rgb(148, 0, 211);
background-color: RGB(148, 0, 211);
border-top-left-radius: 5px;
border-top-right-radius: 5px;
border-bottom-right-radius: 0px;
border-bottom-left-radius: 0px;
"
>
<span style="font-size: 24px; color: rgb(255, 255, 255)"
>xxxxxx系统</span
>
</th>
</tr>
<tr>
<td style="word-break: break-all">
<div
style="
padding: 25px 35px 40px;
background-color: #fff;
opacity: 0.8;
"
>
<h2 style="margin: 5px 0px">
<span style="color: #333333; line-height: 20px">
<span style="line-height: 22px; font-size: 18px">
尊敬的用户:</span
>
</span>
</h2>
<p>
您好!感谢您使用xxxxxx系统,您的账号正在进行邮箱验证,验证码为:<span
style="color: #ff8c00"
><%= code %></span
>,有效期<%= validity %>分钟,请尽快填写验证码完成验证!
</p>
<br />
<div style="width: 100%; margin: 0 auto">
<div
style="
padding: 10px 10px 0;
border-top: 1px solid #ccc;
color: #747474;
margin-bottom: 20px;
line-height: 1.3em;
font-size: 12px;
text-align: right;
"
>
<p>──<%= name %></p>
<br />
<p>
此为系统邮件,请勿回复<br />
Please do not reply to this system email
</p>
<p>©<%= name %></p>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
- 可以检查一下,是否有安装
eslint-plugin-html
这个插件来支持html
文件的检查和解析,没有的需要安装一下
sh
yarn add eslint-plugin-html -D
- 安装完成后,需要在
.eslintrc.js
文件中添加
js
parserOptions: {
extraFileExtensions: ['.html'] // 添加这一行
},
plugins: [
'@typescript-eslint/eslint-plugin',
'eslint-plugin-html',
],
3.4、使用ejs模版
- 想要使用
ejs
模版,用法和使用html
模版也大差不差,需要安装ejs
的解析插件
sh
yarn add eslint-plugin-ejs -D
- 安装完成后,需要在
.eslintrc.js
文件中添加
js
parserOptions: {
extraFileExtensions: ['.ejs'] // 添加这一行
},
plugins: [
'@typescript-eslint/eslint-plugin',
'eslint-plugin-ejs',
],
extends: [
'plugin:eslint-plugin-ejs'
],
-
ejs
页面的代码和html
页面的代码一致 -
以上步骤完成之后,
html
/ejs
页面的报错就会消失 -
在
postman
中发送请求后,可以接收到qq邮箱发送来的验证码