这两天给博客加上了邮件提醒功能,之前用户评论留言之后是没有任何反馈的,体验很不好,用户粘度也会大大降低。现在提醒功能已经上线了,大家都能及时收到回复了!下面分享一下邮件提醒功能在 nestjs 中的实现。


一、邮箱配置

我使用的是大家比较常用的 QQ 邮箱,而要使用 QQ 邮箱的话,需要先登录 QQ 邮箱进行设置,获取到授权码才行,具体操作如下

1- 登录后点击【设置】

1.png


2- 在设置页面选择【账号】

2.png


3- 在账号页面找到【POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务】,然后【开启服务】

3.png


4- 点击【开启服务】后会要求绑定手机号,进行验证。通过后就会给你一个授权码,这个授权码在后续代码中会使用到。不需要记住,通过【管理服务】进入可以查看到已经生成的授权码。

4.png


二、依赖包安装

邮箱配置好后,我们需要安装所需的依赖包,总共四个

dependencies

1- @nestjs-modules/mailer

2- nodemailer

3- nodemailer-smtp-transport


devDependencies

4- @types/nodemailer-smtp-transport


由于使用了 typescript 所以需要安装类型 @types/nodemailer-smtp-transport ,不然会报类型错误。每个人使用的包管理器可能不一样,大家根据自己的情况执行安装就行。我用的是 pnpm

安装生产依赖包

pnpm add @nestjs-modules/mailer nodemailer nodemailer-smtp-transport

安装开发依赖包

pnpm add -D @types/nodemailer-smtp-transport


三、代码开发

准备工作都做完了,现在开始写代码了,找到项目中的 app.module.ts 文件,添加如下代码,进行全局配置

// 引入包
import { MailerModule } from '@nestjs-modules/mailer'
import * as SMTPTransport from 'nodemailer-smtp-transport'

@Module({
    imports: [
        MailerModule.forRoot({
            transport: SMTPTransport({
                host: 'smtp.qq.com',
                port: 465,
                secure: true, // true for 465, false for other ports
                auth: {
                    user: '此处填写你的邮箱',
                    pass: '此处填写上文中拿到的授权码', // 建议放在配置文件,不要直接硬编码写在程序里
                }
            })
        }),
    ]
})

全局配置完成后,就可以在 service 中使用了,在你需要发送邮件的地方加上逻辑即可。比如在用户发表评论后,邮件通知我去审核。

comment.service.ts

// 引入邮件Service
import { MailerService } from '@nestjs-modules/mailer'

// 注入
@Injectable()
export class CommentService {
    constructor(
        private readonly mailerService: MailerService
    ) {}

    async create(createCommentDto: CreateCommentDto) {
        const result = await this.prisma.comment.create({
            data: createCommentDto
        })

        // 发送邮件
        this.mailerService.sendMail({
            from: '此处填写发送人',
            to: '此处填写你的收件箱',
            subject: '博客有新的评论待处理', // 邮件主题
            text: `${createCommentDto.nickName}: ${createCommentDto.content}`, // 邮件内容
        })

        return result
    }
}

需要注意的点:

1- from 必须配置,因为 QQ 邮箱 SMTP 服务对于 from 有严格验证,不配置就会报错。这里我踩了大坑,找了好久的报错原因,因为报错信息并不会提示你需要配置 from,只告诉你参数有误。

2- from 格式与你 QQ 邮箱的名称保持一致,比如我的 QQ 邮箱名称如下图,那么这里我就填写 from: '小贰<aaron.yyf@qq.com>'

5.png


四、邮件内容美化

邮件内容美化,指的就是让你发出去的邮件格式工整,排版美观,可读性更好。其意义就在于给用户一个良好的体验,能更直观的抓住内容重点。邮件内容除了支持 text ,它还支持 html ,而 html 里面是可以写 css 样式的,这样我们就可以通过 html + css 来控制邮件的排版。

上面的示例:发送邮件提醒我审核用户评论。它是没做美化的(直接用的 text),因为是我自己看,所以无所谓,但是发送给用户的邮件是有必要做美化的。先贴一张美化后的图

6.png

怎么样,用户收到这样的邮件是不是很清爽,阅读起来是不是更舒服,比一堆文字放在那里要强上不少吧。需要注意的是,在邮箱里书写 html 和在网页里还不太一样,主要是兼容性问题。在邮箱里通常采用 table 布局,而且样式需要写成内连样式。下面是一个具体的示例:

// 发送邮件
this.mailerService.sendMail({
    from: process.env.EMAIL_FROM, // 从配置文件读取 from
    to: parent.email,
    subject: `您在文章《${article.title}》的评论收到了新的回复`,
    html: 
    `<div style="background-color: #f5f5f5;border-radius: 5px;max-width: 580px;padding: 10px;">
        <table style="width: 100%;border-collapse: collapse;background-color: #fff;">
            <tr>
                <td style="padding:40px 0;">
                    <center>
                        <p style="font-size: 18px;font-weight: bold;">鄢云峰的个人网站</p>
                    </center>
                </td>
            </tr>
            <tr>
                <td style="padding: 0 20px 40px 20px; font-size: 14px;">
                    <p style="color: #666;">您好,${parent.nickName}!你于 ${Utils.dateFormat(parent.createTime)} 在文章《${article.title}》发表的评论:</p>
                    <p style="color: #333;background-color: #eee;padding:20px;border-radius: 4px;">${parent.content}</p>
                </td>
            </tr>
            <tr>
                <td style="padding: 0 20px 40px 20px; font-size: 14px;">
                    <p style="color: #666;">收到了来自于 ${createCommentDto.nickName}${Utils.dateFormat(result.createTime)}) 的回复:</p>
                    <p style="color: #333;background-color: #eee;padding:20px;border-radius: 4px;">${createCommentDto.content}</p>
                </td>
            </tr>
            <tr>
                <td style="padding: 40px 20px; font-size: 14px; color: #666;">
                    <span>查看详情:</span>
                    <a href="https://yanyunfeng.com/article/${article.id}">https://yanyunfeng.com/article/${article.id}</a>
                </td>
            </tr>
            <tr>
                <td style="background-color: #f1f1f1; padding: 20px 0;">
                    <center>
                        <div style="max-width: 600px;">
                            <p style="font-size: 14px; color: #999;">此邮件为系统自动发送,请勿直接回复</p>
                        </div>
                    </center>
                </td>
            </tr>
        </table>
    </div>`
})
本文最后更新于 2024-08-10 11:32:02NODEJS
天生我材必有用,千金散尽还复来~~
作者:鄢云峰 YYF声明:转载请注明文章出处地址:https://yanyunfeng.com/article/54
评论
提交
Comments | 4 条评论
爱吃猫的汉堡2024-08-14 09:16:03
#1 回复
等等绑定一下
鄢云峰站长2024-08-14 09:23:09
#2 回复
@爱吃猫的汉堡 啥意思,绑定什么?
吃猫的汉堡2024-08-14 15:08:02
#3 回复
看错了,以为是这样设置邮箱才能收到发来的邮件:D
鄢云峰站长2024-08-14 15:15:11
#4 回复
@吃猫的汉堡 用户是不需要做任何配置的,留言的时候填写邮箱地址就行了。看来是我文章表述不清晰,让读者误解了😂