node实现邮件发送功能

322 阅读2分钟

简介

早前,我在博客中基于腾讯云sms短信服务实现了一套短信验证码登录功能,但短信是收费的,为了节约成本,我又为博客打造了一套邮箱登录的流程。

准备工作

首先,我们需要有一个用于发送邮件的邮箱,获取该邮箱的服务器地址端口号以及授权码,以网易邮箱为例,在设置中即可找到。 image.png 其次,我们选用nodemailer来发送邮件,它是大多数 Node.js 用户默认使用的解决方案。

代码

配置

// packages\waylon-blog-interfaces\src\config\produciton.ts
export default {
    emailConfig: {
        host: 'smtp.163.com', // 邮箱服务器
        port: 465, // 默认端口
        secure: true, // 如果为true,连接将在连接到服务器时使用 TLS
        auth: {
            user: 'waylon13@163.com', // 发送邮箱
            pass: 'XXXXXXXXXXXXX', // 刚刚生成的校验码
        },
    },
};

Email类

实现一个Email类,用于发送各种形式的邮件

// packages\waylon-blog-interfaces\src\common\email.ts
import * as nodeEmail from 'nodemailer';
// 邮箱类 入参为刚刚配置
export class Email {
    private transporter: object;
    constructor({ host, port, secure, auth }) {
        this.transporter = nodeEmail.createTransport({
            host,
            port,
            secure,
            auth,
        });
    }
    // 真正的发邮件的方法
    async send(options) {
        let info = await (this.transporter as any).sendMail(options);
        return info;
    }
}

使用

这里使用Nest.js框架来实现,这里略过controller与module,着重关注service层逻辑。

ConfigService、CacheService分别用于获取ENV配置与Redis缓存,之前的文章也有介绍过具体实现。

// packages\waylon-blog-interfaces\src\auth\auth.service.ts
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CacheService } from 'src/cache/cache.service';
import { ConfigService } from '@nestjs/config';
import { Email } from 'src/common/email';

@Injectable()
export class AuthService {
    constructor(
        private configService: ConfigService,
        private cacheService: CacheService
    ) {}

  
    // 生成6位验证码
    getRandomCode() {
        return ('000000' + Math.floor(Math.random() * 999999)).slice(-6);
    }
 

    // 发邮箱
    async email(email: string, sense?: number) {
        if (!email) {
            throw new HttpException('邮箱不能为空!', HttpStatus.BAD_REQUEST);
        }
        // 查下redis缓存 10分钟内无法再发邮箱
        const cache = await this.cacheService.getCache(email);
        if (cache) {
            throw new HttpException('手速把不要那么快啊喂![○・`Д´・ ○]', HttpStatus.BAD_REQUEST);
        }
        const emailController = new Email(this.configService.get('emailConfig'));
        const code = this.getRandomCode();
        const options = {
            from: this.configService.get('emailConfig').auth.user, // sender address
            to: email, // list of receivers
            subject: '一封Waylonの邮件', // Subject line
            text: '一封来自Waylon树洞の邮件', // plain text body
            html: `<h1 style="color: blur">Waylonの树洞</h1><p>您的验证码是<b>${code}</b>,验证码保留3分钟,请及时验证~(#^.^#)<p>`, // html body
        };
        const res = await emailController.send(options);
        // 校验邮箱返回
        if (/^250 Mail OK/.test(res.response)) {
            this.cacheService.setCache(email, code, 600);
            return res;
        } else {
            throw new HttpException('邮箱服务报错,请联系站长(〃>皿<)', HttpStatus.BAD_REQUEST);
        }
    }
  
}

效果图

email.jpg 本篇文章简单地讲下发送邮件功能的实现,本人博客也是支持上了邮箱登录,欢迎各大看官前来体验~

参考文档

nodemailer官网: nodemailer.com/about/