Skip to content

使用 Nest 框架接收邮件

邮箱开启 IMAP/SMTP 服务

  • 获取到授权码

收邮件必须安装包

ts
pnpm add imap
pnpm add mailparser

创建一个模块和 services

getemail.module.ts

ts
import { Module, Global } from "@nestjs/common";
import { GetemailService } from "./getemail.service";

@Global()
@Module({
  providers: [GetemailService],
  exports: [GetemailService],
})
export class GetemailModule {}

getemail.service.ts

ts
import { Injectable } from "@nestjs/common";
const { MailParser } = require("mailparser");
const fs = require("fs");
const path = require("path");
const Imap = require("imap");

@Injectable()
export class GetemailService {
  private imap: any;

  constructor() {
    // 初始化IMAP连接,使用配置(建议从配置模块获取)
    this.imap = new Imap({
      user: "2993222085@qq.com", // 接收邮件的邮箱
      password: "hcawwvuevwtldecd", // 接收邮件的授权码
      host: "imap.qq.com", // 接收邮件的邮箱服务器
      port: 993, // 接收邮件的邮箱服务器端口
      tls: true, // 是否使用TLS加密
      tlsOptions: { rejectUnauthorized: false }, // 仅测试环境关闭证书验证
    });
  }

  /**
   * 连接IMAP服务器并设置事件监听
   * 该方法用于建立与邮件服务器的连接,并配置相关的事件处理程序
   */
  connectAndListen() {
    this.imap.connect();

    this.imap.once("ready", () => {
      this.imap.openBox("INBOX", true, (err) => {
        if (err) throw err;
        console.log("连接上了");
        // 监听新邮件事件 我这里就是监听2020-06-10 以后的
        this.imap.search(
          [
            ["SEEN"],
            ["SINCE", new Date("2020-06-10 19:00:00").toLocaleString()],
          ],
          (err, results) => {
            if (!err) {
              console.log(results);
              this.handleResults(results);
            } else {
              throw err;
            }
          }
        );
        // 也可以初始获取一次邮件
      });
    });

    this.imap.once("error", (err: Error) => {
      console.error("IMAP error:", err);
    });

    this.imap.once("end", () => {
      console.log("IMAP connection ended");
    });
  }

  private handleResults(results) {
    this.imap
      .fetch(results, {
        bodies: "",
        markSeen: false,
        struct: true,
      })
      .on("message", (msg) => {
        const mailparser = new MailParser();

        msg.on("body", (stream) => {
          const info: any = {};
          stream.pipe(mailparser);

          mailparser.on("headers", (headers) => {
            info.theme = headers.get("subject");
            info.form = headers.get("from").value[0].address;
            info.mailName = headers.get("from").value[0].name;
            info.to = headers.get("to").value[0].address;
            info.datatime = headers.get("date").toLocaleString();
          });

          mailparser.on("data", (data) => {
            console.log(data.type);
            // 邮件内容
            if (data.type === "text") {
              info.html = data.html;
              info.text = data.text;
              // console.log(info);
              const fileFloder = "./src/modules/getemail/mails"; // 保存邮件的内容
              const filePath = path.join(fileFloder, info.theme + ".html");
              fs.writeFileSync(filePath, info.html || info.text); // 保存邮件内容到文件
            }
            // 邮件附件
            if (data.type === "attachment") {
              // const filePath = path.join(__dirname, 'files', data.filename);
              const dir = "./src/modules/getemail/files"; // 下载目录
              const filePath = path.join(dir, data.filename);
              const ws = fs.createWriteStream(filePath);
              data.content.pipe(ws);
            }
          });
        });
      });
  }
}

其他搜寻条件可以看 文档

使用

其他模块

其他.service.ts

ts
  // 接收邮件
  async getemail() {
    const result = await this.getemailService.connectAndListen();
    return result;
  }

其他.controller.ts

ts
  // 接收邮件
  @Post('getemail')
  async getemail() {
    const result = await this.userService.getemail();
    return {
      data: result,
    };
  }