- 统一文件命名为snake_case格式(kebab-case snake_case) - 重构zulip模块为zulip_core,明确Core层职责 - 重构user-mgmt模块为user_mgmt,统一命名规范 - 调整模块依赖关系,优化架构分层 - 删除过时的文件和目录结构 - 更新相关文档和配置文件 本次重构涉及大量文件重命名和模块重组, 旨在建立更清晰的项目架构和统一的命名规范。
596 lines
21 KiB
TypeScript
596 lines
21 KiB
TypeScript
/**
|
||
* 邮件服务
|
||
*
|
||
* 功能描述:
|
||
* - 提供邮件发送的核心功能
|
||
* - 支持多种邮件模板和场景
|
||
* - 集成主流邮件服务提供商
|
||
*
|
||
* 支持的邮件类型:
|
||
* - 邮箱验证码
|
||
* - 密码重置验证码
|
||
* - 欢迎邮件
|
||
* - 系统通知
|
||
*
|
||
* 职责分离:
|
||
* - 邮件发送:核心邮件发送功能实现
|
||
* - 模板管理:各种邮件模板的生成和管理
|
||
* - 配置管理:邮件服务配置和连接管理
|
||
*
|
||
* 最近修改:
|
||
* - 2026-01-07: 代码规范优化 - 清理未使用的导入(BadRequestException),移除多余注释
|
||
* - 2026-01-07: 代码规范优化 - 完善方法注释和修改记录
|
||
*
|
||
* @author moyin
|
||
* @version 1.0.1
|
||
* @since 2025-12-17
|
||
* @lastModified 2026-01-07
|
||
*/
|
||
|
||
import { Injectable, Logger } from '@nestjs/common';
|
||
import { ConfigService } from '@nestjs/config';
|
||
import * as nodemailer from 'nodemailer';
|
||
import { Transporter } from 'nodemailer';
|
||
|
||
/**
|
||
* 邮件发送选项接口
|
||
*/
|
||
export interface EmailOptions {
|
||
/** 收件人邮箱 */
|
||
to: string;
|
||
/** 邮件主题 */
|
||
subject: string;
|
||
/** 邮件内容(HTML格式) */
|
||
html: string;
|
||
/** 邮件内容(纯文本格式) */
|
||
text?: string;
|
||
}
|
||
|
||
/**
|
||
* 验证码邮件选项接口
|
||
*/
|
||
export interface VerificationEmailOptions {
|
||
/** 收件人邮箱 */
|
||
email: string;
|
||
/** 验证码 */
|
||
code: string;
|
||
/** 用户昵称 */
|
||
nickname?: string;
|
||
/** 验证码用途 */
|
||
purpose: 'email_verification' | 'password_reset' | 'login_verification';
|
||
}
|
||
|
||
/**
|
||
* 邮件发送结果接口
|
||
*/
|
||
export interface EmailSendResult {
|
||
/** 是否成功 */
|
||
success: boolean;
|
||
/** 是否为测试模式 */
|
||
isTestMode: boolean;
|
||
/** 错误信息(如果失败) */
|
||
error?: string;
|
||
}
|
||
|
||
/**
|
||
* 邮件服务类
|
||
*
|
||
* 职责:
|
||
* - 邮件发送功能:提供统一的邮件发送接口
|
||
* - 模板管理:管理各种邮件模板(验证码、欢迎邮件等)
|
||
* - 配置管理:处理邮件服务配置和连接
|
||
* - 测试模式:支持开发环境的邮件测试模式
|
||
*
|
||
* 主要方法:
|
||
* - sendEmail() - 通用邮件发送方法
|
||
* - sendVerificationCode() - 发送验证码邮件
|
||
* - sendWelcomeEmail() - 发送欢迎邮件
|
||
* - verifyConnection() - 验证邮件服务连接
|
||
*
|
||
* 使用场景:
|
||
* - 用户注册时发送邮箱验证码
|
||
* - 密码重置时发送重置验证码
|
||
* - 用户注册成功后发送欢迎邮件
|
||
* - 登录验证时发送登录验证码
|
||
*/
|
||
@Injectable()
|
||
export class EmailService {
|
||
private readonly logger = new Logger(EmailService.name);
|
||
private transporter: Transporter;
|
||
|
||
constructor(private readonly configService: ConfigService) {
|
||
this.initializeTransporter();
|
||
}
|
||
|
||
/**
|
||
* 初始化邮件传输器
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 从配置服务获取邮件服务配置(主机、端口、安全设置、认证信息)
|
||
* 2. 检查是否配置了用户名和密码
|
||
* 3. 未配置:创建测试模式传输器(streamTransport)
|
||
* 4. 已配置:创建真实SMTP传输器
|
||
* 5. 记录初始化结果到日志
|
||
* 6. 设置transporter实例
|
||
*/
|
||
private initializeTransporter(): void {
|
||
const emailConfig = {
|
||
host: this.configService.get<string>('EMAIL_HOST', 'smtp.gmail.com'),
|
||
port: this.configService.get<number>('EMAIL_PORT', 587),
|
||
secure: this.configService.get<boolean>('EMAIL_SECURE', false), // true for 465, false for other ports
|
||
auth: {
|
||
user: this.configService.get<string>('EMAIL_USER'),
|
||
pass: this.configService.get<string>('EMAIL_PASS'),
|
||
},
|
||
};
|
||
|
||
// 如果没有配置邮件服务,使用测试模式
|
||
if (!emailConfig.auth.user || !emailConfig.auth.pass) {
|
||
this.logger.warn('邮件服务未配置,将使用测试模式(邮件不会真实发送)');
|
||
this.transporter = nodemailer.createTransport({
|
||
streamTransport: true,
|
||
newline: 'unix',
|
||
buffer: true
|
||
});
|
||
} else {
|
||
this.transporter = nodemailer.createTransport(emailConfig);
|
||
this.logger.log('邮件服务初始化成功');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查是否为测试模式
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 检查transporter的options配置
|
||
* 2. 判断是否设置了streamTransport选项
|
||
* 3. streamTransport为true表示测试模式
|
||
* 4. 返回测试模式状态
|
||
*
|
||
* @returns 是否为测试模式,true表示测试模式,false表示生产模式
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* if (emailService.isTestMode()) {
|
||
* console.log('当前为测试模式,邮件不会真实发送');
|
||
* }
|
||
* ```
|
||
*/
|
||
isTestMode(): boolean {
|
||
return !!(this.transporter.options as any).streamTransport;
|
||
}
|
||
|
||
/**
|
||
* 发送邮件
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 构建邮件选项(发件人、收件人、主题、内容)
|
||
* 2. 检查是否为测试模式
|
||
* 3. 测试模式:输出邮件内容到控制台,不真实发送
|
||
* 4. 生产模式:通过SMTP服务器发送邮件
|
||
* 5. 记录发送结果和错误信息
|
||
* 6. 返回发送结果状态
|
||
*
|
||
* @param options 邮件选项
|
||
* @returns 发送结果,包含成功状态、测试模式标识和错误信息
|
||
* @throws Error 当邮件发送失败时抛出错误(已捕获并返回在结果中)
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* const result = await emailService.sendEmail({
|
||
* to: 'user@example.com',
|
||
* subject: '测试邮件',
|
||
* html: '<p>邮件内容</p>',
|
||
* text: '邮件内容'
|
||
* });
|
||
* if (result.success) {
|
||
* console.log('邮件发送成功');
|
||
* }
|
||
* ```
|
||
*/
|
||
async sendEmail(options: EmailOptions): Promise<EmailSendResult> {
|
||
try {
|
||
const mailOptions = {
|
||
from: this.configService.get<string>('EMAIL_FROM', '"Whale Town Game" <noreply@whaletown.com>'),
|
||
to: options.to,
|
||
subject: options.subject,
|
||
html: options.html,
|
||
text: options.text,
|
||
};
|
||
|
||
const isTestMode = this.isTestMode();
|
||
|
||
// 如果是测试模式,输出邮件内容到控制台
|
||
if (isTestMode) {
|
||
this.logger.warn('=== 邮件发送(测试模式 - 邮件未真实发送) ===');
|
||
this.logger.warn(`收件人: ${options.to}`);
|
||
this.logger.warn(`主题: ${options.subject}`);
|
||
this.logger.warn(`内容: ${options.text || '请查看HTML内容'}`);
|
||
this.logger.warn('⚠️ 注意: 这是测试模式,邮件不会真实发送到用户邮箱');
|
||
this.logger.warn('💡 提示: 请在 .env 文件中配置邮件服务以启用真实发送');
|
||
this.logger.warn('================================================');
|
||
return { success: true, isTestMode: true };
|
||
}
|
||
|
||
// 真实发送邮件
|
||
const result = await this.transporter.sendMail(mailOptions);
|
||
this.logger.log(`✅ 邮件发送成功: ${options.to}`);
|
||
return { success: true, isTestMode: false };
|
||
} catch (error) {
|
||
this.logger.error(`❌ 邮件发送失败: ${options.to}`, error instanceof Error ? error.stack : String(error));
|
||
return {
|
||
success: false,
|
||
isTestMode: this.isTestMode(),
|
||
error: error instanceof Error ? error.message : String(error)
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送邮箱验证码
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 根据验证码用途选择对应的邮件主题和模板
|
||
* 2. 邮箱验证:使用邮箱验证模板
|
||
* 3. 密码重置:使用密码重置模板
|
||
* 4. 登录验证:使用登录验证模板
|
||
* 5. 生成HTML邮件内容和纯文本内容
|
||
* 6. 调用sendEmail方法发送邮件
|
||
* 7. 返回发送结果
|
||
*
|
||
* @param options 验证码邮件选项
|
||
* @returns 发送结果,包含成功状态和错误信息
|
||
* @throws Error 当邮件发送失败时(已捕获并返回在结果中)
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* const result = await emailService.sendVerificationCode({
|
||
* email: 'user@example.com',
|
||
* code: '123456',
|
||
* nickname: '张三',
|
||
* purpose: 'email_verification'
|
||
* });
|
||
* ```
|
||
*/
|
||
async sendVerificationCode(options: VerificationEmailOptions): Promise<EmailSendResult> {
|
||
const { email, code, nickname, purpose } = options;
|
||
|
||
let subject: string;
|
||
let template: string;
|
||
|
||
if (purpose === 'email_verification') {
|
||
subject = '【Whale Town】邮箱验证码';
|
||
template = this.getEmailVerificationTemplate(code, nickname);
|
||
} else if (purpose === 'password_reset') {
|
||
subject = '【Whale Town】密码重置验证码';
|
||
template = this.getPasswordResetTemplate(code, nickname);
|
||
} else if (purpose === 'login_verification') {
|
||
subject = '【Whale Town】登录验证码';
|
||
template = this.getLoginVerificationTemplate(code, nickname);
|
||
} else {
|
||
subject = '【Whale Town】验证码';
|
||
template = this.getEmailVerificationTemplate(code, nickname);
|
||
}
|
||
|
||
return await this.sendEmail({
|
||
to: email,
|
||
subject,
|
||
html: template,
|
||
text: `您的验证码是:${code},5分钟内有效,请勿泄露给他人。`
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 发送欢迎邮件
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 设置欢迎邮件主题
|
||
* 2. 生成包含用户昵称的欢迎邮件模板
|
||
* 3. 模板包含游戏特色介绍(建造创造、社交互动、任务挑战)
|
||
* 4. 调用sendEmail方法发送邮件
|
||
* 5. 返回发送结果
|
||
*
|
||
* @param email 邮箱地址
|
||
* @param nickname 用户昵称
|
||
* @returns 发送结果,包含成功状态和错误信息
|
||
* @throws Error 当邮件发送失败时(已捕获并返回在结果中)
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* const result = await emailService.sendWelcomeEmail(
|
||
* 'newuser@example.com',
|
||
* '新用户'
|
||
* );
|
||
* ```
|
||
*/
|
||
async sendWelcomeEmail(email: string, nickname: string): Promise<EmailSendResult> {
|
||
const subject = '🎮 欢迎加入 Whale Town!';
|
||
const template = this.getWelcomeTemplate(nickname);
|
||
|
||
return await this.sendEmail({
|
||
to: email,
|
||
subject,
|
||
html: template,
|
||
text: `欢迎 ${nickname} 加入 Whale Town 像素游戏世界!`
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取邮箱验证模板
|
||
*
|
||
* @param code 验证码
|
||
* @param nickname 用户昵称
|
||
* @returns HTML模板
|
||
*/
|
||
private getEmailVerificationTemplate(code: string, nickname?: string): string {
|
||
return `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>邮箱验证</title>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
||
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
||
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }
|
||
.content { background: #f9f9f9; padding: 30px; border-radius: 0 0 10px 10px; }
|
||
.code-box { background: #fff; border: 2px dashed #667eea; padding: 20px; text-align: center; margin: 20px 0; border-radius: 8px; }
|
||
.code { font-size: 32px; font-weight: bold; color: #667eea; letter-spacing: 5px; }
|
||
.footer { text-align: center; margin-top: 20px; color: #666; font-size: 12px; }
|
||
.warning { background: #fff3cd; border: 1px solid #ffeaa7; padding: 15px; border-radius: 5px; margin: 20px 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1>🐋 Whale Town</h1>
|
||
<p>邮箱验证</p>
|
||
</div>
|
||
<div class="content">
|
||
<h2>你好${nickname ? ` ${nickname}` : ''}!</h2>
|
||
<p>感谢您注册 Whale Town 像素游戏!为了确保您的账户安全,请使用以下验证码完成邮箱验证:</p>
|
||
|
||
<div class="code-box">
|
||
<div class="code">${code}</div>
|
||
<p style="margin: 10px 0 0 0; color: #666;">验证码</p>
|
||
</div>
|
||
|
||
<div class="warning">
|
||
<strong>⚠️ 安全提醒:</strong>
|
||
<ul style="margin: 10px 0 0 20px;">
|
||
<li>验证码 5 分钟内有效</li>
|
||
<li>请勿将验证码泄露给他人</li>
|
||
<li>如非本人操作,请忽略此邮件</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<p>完成验证后,您就可以开始您的像素世界冒险之旅了!</p>
|
||
</div>
|
||
<div class="footer">
|
||
<p>此邮件由系统自动发送,请勿回复</p>
|
||
<p>© 2025 Whale Town Game. All rights reserved.</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>`;
|
||
}
|
||
|
||
/**
|
||
* 获取密码重置模板
|
||
*
|
||
* @param code 验证码
|
||
* @param nickname 用户昵称
|
||
* @returns HTML模板
|
||
*/
|
||
private getPasswordResetTemplate(code: string, nickname?: string): string {
|
||
return `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>密码重置</title>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
||
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
||
.header { background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%); color: white; padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }
|
||
.content { background: #f9f9f9; padding: 30px; border-radius: 0 0 10px 10px; }
|
||
.code-box { background: #fff; border: 2px dashed #ff6b6b; padding: 20px; text-align: center; margin: 20px 0; border-radius: 8px; }
|
||
.code { font-size: 32px; font-weight: bold; color: #ff6b6b; letter-spacing: 5px; }
|
||
.footer { text-align: center; margin-top: 20px; color: #666; font-size: 12px; }
|
||
.warning { background: #fff3cd; border: 1px solid #ffeaa7; padding: 15px; border-radius: 5px; margin: 20px 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1>🔐 密码重置</h1>
|
||
<p>Whale Town 账户安全</p>
|
||
</div>
|
||
<div class="content">
|
||
<h2>你好${nickname ? ` ${nickname}` : ''}!</h2>
|
||
<p>我们收到了您的密码重置请求。请使用以下验证码来重置您的密码:</p>
|
||
|
||
<div class="code-box">
|
||
<div class="code">${code}</div>
|
||
<p style="margin: 10px 0 0 0; color: #666;">密码重置验证码</p>
|
||
</div>
|
||
|
||
<div class="warning">
|
||
<strong>🛡️ 安全提醒:</strong>
|
||
<ul style="margin: 10px 0 0 20px;">
|
||
<li>验证码 5 分钟内有效</li>
|
||
<li>请勿将验证码泄露给他人</li>
|
||
<li>如非本人操作,请立即联系客服</li>
|
||
<li>重置密码后请妥善保管新密码</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<p>如果您没有请求重置密码,请忽略此邮件,您的账户仍然安全。</p>
|
||
</div>
|
||
<div class="footer">
|
||
<p>此邮件由系统自动发送,请勿回复</p>
|
||
<p>© 2025 Whale Town Game. All rights reserved.</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>`;
|
||
}
|
||
|
||
/**
|
||
* 获取登录验证码模板
|
||
*
|
||
* @param code 验证码
|
||
* @param nickname 用户昵称
|
||
* @returns HTML模板
|
||
*/
|
||
private getLoginVerificationTemplate(code: string, nickname?: string): string {
|
||
return `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>登录验证码</title>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
||
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
||
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }
|
||
.content { background: #f9f9f9; padding: 30px; border-radius: 0 0 10px 10px; }
|
||
.code-box { background: #fff; border: 2px dashed #667eea; padding: 20px; text-align: center; margin: 20px 0; border-radius: 8px; }
|
||
.code { font-size: 32px; font-weight: bold; color: #667eea; letter-spacing: 5px; }
|
||
.footer { text-align: center; margin-top: 20px; color: #666; font-size: 12px; }
|
||
.info { background: #e3f2fd; border: 1px solid #bbdefb; padding: 15px; border-radius: 5px; margin: 20px 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1>🔐 登录验证码</h1>
|
||
<p>Whale Town 安全登录</p>
|
||
</div>
|
||
<div class="content">
|
||
<h2>你好${nickname ? ` ${nickname}` : ''}!</h2>
|
||
<p>您正在使用验证码登录 Whale Town。请使用以下验证码完成登录:</p>
|
||
|
||
<div class="code-box">
|
||
<div class="code">${code}</div>
|
||
<p style="margin: 10px 0 0 0; color: #666;">登录验证码</p>
|
||
</div>
|
||
|
||
<div class="info">
|
||
<strong>📱 使用说明:</strong>
|
||
<ul style="margin: 10px 0 0 20px;">
|
||
<li>验证码 5 分钟内有效</li>
|
||
<li>请在登录页面输入此验证码</li>
|
||
<li>验证码仅限本次登录使用</li>
|
||
<li>请勿将验证码泄露给他人</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<p>如果您没有尝试登录,请忽略此邮件,或联系客服确认账户安全。</p>
|
||
</div>
|
||
<div class="footer">
|
||
<p>此邮件由系统自动发送,请勿回复</p>
|
||
<p>© 2025 Whale Town Game. All rights reserved.</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>`;
|
||
}
|
||
|
||
/**
|
||
* 获取欢迎邮件模板
|
||
*
|
||
* @param nickname 用户昵称
|
||
* @returns HTML模板
|
||
*/
|
||
private getWelcomeTemplate(nickname: string): string {
|
||
return `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>欢迎加入 Whale Town</title>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
||
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
||
.header { background: linear-gradient(135deg, #4ecdc4 0%, #44a08d 100%); color: white; padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }
|
||
.content { background: #f9f9f9; padding: 30px; border-radius: 0 0 10px 10px; }
|
||
.feature-box { background: #fff; padding: 20px; margin: 15px 0; border-radius: 8px; border-left: 4px solid #4ecdc4; }
|
||
.footer { text-align: center; margin-top: 20px; color: #666; font-size: 12px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1>🎮 欢迎加入 Whale Town!</h1>
|
||
<p>像素世界的冒险即将开始</p>
|
||
</div>
|
||
<div class="content">
|
||
<h2>欢迎你,${nickname}!</h2>
|
||
<p>恭喜您成功注册 Whale Town 像素游戏!您现在已经成为我们像素世界大家庭的一员了。</p>
|
||
|
||
<div class="feature-box">
|
||
<h3>🏗️ 建造与创造</h3>
|
||
<p>在像素世界中建造您的梦想家园,发挥无限创意!</p>
|
||
</div>
|
||
|
||
<div class="feature-box">
|
||
<h3>🤝 社交互动</h3>
|
||
<p>与其他玩家交流互动,结交志同道合的朋友!</p>
|
||
</div>
|
||
|
||
<div class="feature-box">
|
||
<h3>🎯 任务挑战</h3>
|
||
<p>完成各种有趣的任务,获得丰厚的奖励!</p>
|
||
</div>
|
||
|
||
<p><strong>现在就开始您的像素冒险之旅吧!</strong></p>
|
||
<p>如果您在游戏过程中遇到任何问题,随时可以联系我们的客服团队。</p>
|
||
</div>
|
||
<div class="footer">
|
||
<p>祝您游戏愉快!</p>
|
||
<p>© 2025 Whale Town Game. All rights reserved.</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>`;
|
||
}
|
||
|
||
/**
|
||
* 验证邮件服务配置
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 调用transporter的verify方法测试连接
|
||
* 2. 验证SMTP服务器连接是否正常
|
||
* 3. 验证认证信息是否有效
|
||
* 4. 记录验证结果到日志
|
||
* 5. 返回验证结果状态
|
||
*
|
||
* @returns 验证结果,true表示连接成功,false表示连接失败
|
||
* @throws Error 当连接验证失败时(已捕获并返回false)
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* const isConnected = await emailService.verifyConnection();
|
||
* if (isConnected) {
|
||
* console.log('邮件服务连接正常');
|
||
* } else {
|
||
* console.log('邮件服务连接失败');
|
||
* }
|
||
* ```
|
||
*/
|
||
async verifyConnection(): Promise<boolean> {
|
||
try {
|
||
await this.transporter.verify();
|
||
this.logger.log('邮件服务连接验证成功');
|
||
return true;
|
||
} catch (error) {
|
||
this.logger.error('邮件服务连接验证失败', error instanceof Error ? error.stack : String(error));
|
||
return false;
|
||
}
|
||
}
|
||
} |