fix: 修复QQ邮箱From字段格式问题
- 修正From字段配置,确保邮箱地址与SMTP认证用户一致 - 添加fromName支持,支持自定义发件人显示名称 - 改进From字段格式化,符合RFC5322标准 - 添加配置验证,防止空邮箱地址错误 - 创建QQ邮箱配置指南和测试demo 解决550 From header错误,完善邮件服务
This commit is contained in:
parent
0a74b7fb35
commit
c6a3ad5332
104
qq-email-setup.md
Normal file
104
qq-email-setup.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# QQ邮箱配置指南
|
||||||
|
|
||||||
|
## 🚨 问题原因
|
||||||
|
错误 `550 The "From" header is missing or invalid` 是因为QQ邮箱要求:
|
||||||
|
1. **From字段的邮箱地址必须与SMTP认证用户名完全一致**
|
||||||
|
2. **From字段格式必须符合RFC5322标准**
|
||||||
|
|
||||||
|
## ⚙️ 正确配置步骤
|
||||||
|
|
||||||
|
### 第一步:获取QQ邮箱授权码
|
||||||
|
|
||||||
|
1. 登录 [QQ邮箱网页版](https://mail.qq.com/)
|
||||||
|
2. 点击右上角 **设置** → **账户**
|
||||||
|
3. 找到 **"POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务"**
|
||||||
|
4. 开启 **"IMAP/SMTP服务"**
|
||||||
|
5. 按提示发送短信验证
|
||||||
|
6. 获得16位授权码(例如:`abcdefghijklmnop`)
|
||||||
|
|
||||||
|
### 第二步:创建.env文件
|
||||||
|
|
||||||
|
在项目根目录创建 `.env` 文件,内容如下:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# QQ邮箱SMTP配置
|
||||||
|
SMTP_HOST=smtp.qq.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_SECURE=false
|
||||||
|
|
||||||
|
# 认证信息(重要:必须使用相同的邮箱地址)
|
||||||
|
SMTP_USER=your_qq_email@qq.com
|
||||||
|
SMTP_PASS=your_16_digit_authorization_code
|
||||||
|
|
||||||
|
# 发件人信息(重要:邮箱地址必须与SMTP_USER一致)
|
||||||
|
SMTP_FROM_EMAIL=your_qq_email@qq.com
|
||||||
|
SMTP_FROM_NAME=星撰系统
|
||||||
|
|
||||||
|
# 其他配置
|
||||||
|
EMAIL_REPLY_TO=your_qq_email@qq.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### 第三步:替换为你的真实信息
|
||||||
|
|
||||||
|
**示例配置:**
|
||||||
|
```env
|
||||||
|
SMTP_HOST=smtp.qq.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_SECURE=false
|
||||||
|
SMTP_USER=123456789@qq.com
|
||||||
|
SMTP_PASS=abcdefghijklmnop
|
||||||
|
SMTP_FROM_EMAIL=123456789@qq.com
|
||||||
|
SMTP_FROM_NAME=星撰系统
|
||||||
|
EMAIL_REPLY_TO=123456789@qq.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## ✅ 配置要点
|
||||||
|
|
||||||
|
1. **SMTP_USER** 和 **SMTP_FROM_EMAIL** 必须是同一个QQ邮箱
|
||||||
|
2. **SMTP_PASS** 是16位授权码,不是QQ登录密码
|
||||||
|
3. **SMTP_FROM_NAME** 可以自定义,这是邮件显示的发件人名称
|
||||||
|
|
||||||
|
## 🧪 测试配置
|
||||||
|
|
||||||
|
配置完成后,运行测试:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 快速测试
|
||||||
|
bun run quick-email-test.ts your_receive_email@example.com
|
||||||
|
|
||||||
|
# 详细测试
|
||||||
|
bun run src/tests/demo/emailDemo.ts your_receive_email@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 常见问题
|
||||||
|
|
||||||
|
### Q: 为什么要用授权码而不是QQ密码?
|
||||||
|
A: QQ邮箱的安全策略,第三方应用必须使用授权码
|
||||||
|
|
||||||
|
### Q: 授权码在哪里生成?
|
||||||
|
A: QQ邮箱设置 → 账户 → 开启IMAP/SMTP服务时生成
|
||||||
|
|
||||||
|
### Q: 为什么From地址必须与SMTP_USER一致?
|
||||||
|
A: QQ邮箱的反欺诈机制,防止伪造发件人
|
||||||
|
|
||||||
|
### Q: 可以使用其他邮箱服务吗?
|
||||||
|
A: 可以,修改SMTP_HOST即可:
|
||||||
|
- 163邮箱:`smtp.163.com`
|
||||||
|
- Gmail:`smtp.gmail.com`
|
||||||
|
- 企业邮箱:根据提供商配置
|
||||||
|
|
||||||
|
## 📝 配置模板
|
||||||
|
|
||||||
|
复制以下内容到 `.env` 文件:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# 请替换为你的真实信息
|
||||||
|
SMTP_HOST=smtp.qq.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_SECURE=false
|
||||||
|
SMTP_USER=替换为你的QQ邮箱@qq.com
|
||||||
|
SMTP_PASS=替换为你的16位授权码
|
||||||
|
SMTP_FROM_EMAIL=替换为你的QQ邮箱@qq.com
|
||||||
|
SMTP_FROM_NAME=星撰系统
|
||||||
|
EMAIL_REPLY_TO=替换为你的QQ邮箱@qq.com
|
||||||
|
```
|
59
quick-email-test.ts
Normal file
59
quick-email-test.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* 快速邮件测试脚本
|
||||||
|
* 运行方式: bun run quick-email-test.ts your@email.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
initializeEmailService,
|
||||||
|
sendEmail,
|
||||||
|
closeEmailService
|
||||||
|
} from './src/plugins/email/email.service';
|
||||||
|
|
||||||
|
async function quickTest() {
|
||||||
|
const testEmail = process.argv[2];
|
||||||
|
|
||||||
|
if (!testEmail) {
|
||||||
|
console.log('❌ 请提供邮箱地址');
|
||||||
|
console.log('💡 使用方法: bun run quick-email-test.ts your@email.com');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📧 快速邮件测试开始...');
|
||||||
|
console.log(`🎯 目标邮箱: ${testEmail}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 初始化邮件服务
|
||||||
|
console.log('🚀 初始化邮件服务...');
|
||||||
|
await initializeEmailService();
|
||||||
|
console.log('✅ 初始化成功');
|
||||||
|
|
||||||
|
// 发送测试邮件
|
||||||
|
console.log('📮 发送测试邮件...');
|
||||||
|
const result = await sendEmail({
|
||||||
|
to: testEmail,
|
||||||
|
subject: '🧪 邮件服务测试',
|
||||||
|
html: `
|
||||||
|
<h2>🎉 邮件测试成功!</h2>
|
||||||
|
<p>如果您收到这封邮件,说明邮件服务配置正确。</p>
|
||||||
|
<p><small>发送时间: ${new Date().toLocaleString('zh-CN')}</small></p>
|
||||||
|
`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
console.log('✅ 邮件发送成功!');
|
||||||
|
console.log(`📮 消息ID: ${result.messageId}`);
|
||||||
|
console.log('📬 请检查您的邮箱收件箱(包括垃圾邮件文件夹)');
|
||||||
|
} else {
|
||||||
|
console.log('❌ 邮件发送失败');
|
||||||
|
console.log(`💥 错误: ${result.error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('💥 执行失败:', error);
|
||||||
|
} finally {
|
||||||
|
await closeEmailService();
|
||||||
|
console.log('🔚 服务已关闭');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickTest();
|
@ -41,10 +41,12 @@ export const smtpConfig = {
|
|||||||
* @property {string} charset - 字符编码
|
* @property {string} charset - 字符编码
|
||||||
*/
|
*/
|
||||||
export const emailConfig = {
|
export const emailConfig = {
|
||||||
/** 发件人信息 */
|
/** 发件人信息 - QQ邮箱要求From地址必须与SMTP用户名一致 */
|
||||||
from: process.env.EMAIL_FROM || `"星撰系统" <${smtpConfig.auth.user}>`,
|
from: process.env.SMTP_FROM_EMAIL || process.env.SMTP_USER || '',
|
||||||
|
/** 发件人名称 */
|
||||||
|
fromName: process.env.SMTP_FROM_NAME || '星撰系统',
|
||||||
/** 回复邮箱 */
|
/** 回复邮箱 */
|
||||||
replyTo: process.env.EMAIL_REPLY_TO || smtpConfig.auth.user,
|
replyTo: process.env.EMAIL_REPLY_TO || process.env.SMTP_USER || '',
|
||||||
/** 字符编码 */
|
/** 字符编码 */
|
||||||
charset: 'utf-8',
|
charset: 'utf-8',
|
||||||
/** 邮件优先级 */
|
/** 邮件优先级 */
|
||||||
@ -61,29 +63,29 @@ export const emailConfig = {
|
|||||||
export const emailTemplates = {
|
export const emailTemplates = {
|
||||||
/** 账号激活邮件模板 */
|
/** 账号激活邮件模板 */
|
||||||
activation: {
|
activation: {
|
||||||
subject: '请激活您的账户 - 星撰系统',
|
subject: '请激活您的账户 - 星撰玉衡',
|
||||||
template: 'activation',
|
template: 'activation',
|
||||||
expireTime: 24 * 60 * 60 * 1000, // 24小时
|
expireTime: 24 * 60 * 60 * 1000, // 24小时
|
||||||
},
|
},
|
||||||
/** 密码重置邮件模板 */
|
/** 密码重置邮件模板 */
|
||||||
passwordReset: {
|
passwordReset: {
|
||||||
subject: '重置您的密码 - 星撰系统',
|
subject: '重置您的密码 - 星撰玉衡',
|
||||||
template: 'password-reset',
|
template: 'password-reset',
|
||||||
expireTime: 30 * 60 * 1000, // 30分钟
|
expireTime: 30 * 60 * 1000, // 30分钟
|
||||||
},
|
},
|
||||||
/** 欢迎邮件模板 */
|
/** 欢迎邮件模板 */
|
||||||
welcome: {
|
welcome: {
|
||||||
subject: '欢迎加入星撰系统',
|
subject: '欢迎加入星撰玉衡',
|
||||||
template: 'welcome',
|
template: 'welcome',
|
||||||
},
|
},
|
||||||
/** 通知邮件模板 */
|
/** 通知邮件模板 */
|
||||||
notification: {
|
notification: {
|
||||||
subject: '系统通知 - 星撰系统',
|
subject: '系统通知 - 星撰玉衡',
|
||||||
template: 'notification',
|
template: 'notification',
|
||||||
},
|
},
|
||||||
/** 密码修改通知模板 */
|
/** 密码修改通知模板 */
|
||||||
passwordChanged: {
|
passwordChanged: {
|
||||||
subject: '密码已修改 - 星撰系统',
|
subject: '密码已修改 - 星撰玉衡',
|
||||||
template: 'password-changed',
|
template: 'password-changed',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -131,6 +131,22 @@ export class EmailService {
|
|||||||
this.validateConfig();
|
this.validateConfig();
|
||||||
this.updateStatus('unhealthy', 'disconnected');
|
this.updateStatus('unhealthy', 'disconnected');
|
||||||
|
|
||||||
|
console.log({
|
||||||
|
host: smtpConfig.host,
|
||||||
|
port: smtpConfig.port,
|
||||||
|
secure: smtpConfig.secure,
|
||||||
|
auth: {
|
||||||
|
user: smtpConfig.auth.user,
|
||||||
|
pass: smtpConfig.auth.pass,
|
||||||
|
},
|
||||||
|
connectionTimeout: smtpConfig.connectionTimeout,
|
||||||
|
greetingTimeout: smtpConfig.greetingTimeout,
|
||||||
|
socketTimeout: smtpConfig.socketTimeout,
|
||||||
|
pool: true, // 使用连接池
|
||||||
|
maxConnections: 5, // 最大连接数
|
||||||
|
maxMessages: 100, // 每个连接最大消息数
|
||||||
|
})
|
||||||
|
|
||||||
// 创建邮件传输器
|
// 创建邮件传输器
|
||||||
this._transporter = nodemailer.createTransport({
|
this._transporter = nodemailer.createTransport({
|
||||||
host: smtpConfig.host,
|
host: smtpConfig.host,
|
||||||
@ -184,9 +200,19 @@ export class EmailService {
|
|||||||
throw new Error('邮件传输器未初始化');
|
throw new Error('邮件传输器未初始化');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 准备邮件选项
|
// 准备邮件选项 - 确保From字段格式正确
|
||||||
|
const fromAddress = options.from || emailConfig.from;
|
||||||
|
if (!fromAddress) {
|
||||||
|
throw new Error('发件人邮箱地址不能为空,请检查SMTP_USER或SMTP_FROM_EMAIL环境变量');
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromName = emailConfig.fromName || '星撰系统';
|
||||||
|
const formattedFrom = fromAddress.includes('<')
|
||||||
|
? fromAddress
|
||||||
|
: `"${fromName}" <${fromAddress}>`;
|
||||||
|
|
||||||
const mailOptions = {
|
const mailOptions = {
|
||||||
from: options.from || emailConfig.from,
|
from: formattedFrom,
|
||||||
to: Array.isArray(options.to) ? options.to.join(', ') : options.to,
|
to: Array.isArray(options.to) ? options.to.join(', ') : options.to,
|
||||||
cc: options.cc ? (Array.isArray(options.cc) ? options.cc.join(', ') : options.cc) : undefined,
|
cc: options.cc ? (Array.isArray(options.cc) ? options.cc.join(', ') : options.cc) : undefined,
|
||||||
bcc: options.bcc ? (Array.isArray(options.bcc) ? options.bcc.join(', ') : options.bcc) : undefined,
|
bcc: options.bcc ? (Array.isArray(options.bcc) ? options.bcc.join(', ') : options.bcc) : undefined,
|
||||||
|
213
src/tests/demo/emailDemo.ts
Normal file
213
src/tests/demo/emailDemo.ts
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/**
|
||||||
|
* @file 邮件发送Demo
|
||||||
|
* @author hotok
|
||||||
|
* @date 2025-06-29
|
||||||
|
* @description 简单的邮件发送测试demo,用于验证邮件服务是否正常工作
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
initializeEmailService,
|
||||||
|
sendEmail,
|
||||||
|
sendTemplateEmail,
|
||||||
|
checkEmailServiceHealth,
|
||||||
|
closeEmailService
|
||||||
|
} from '@/plugins/email/email.service';
|
||||||
|
import { validateEmailConfig } from '@/config/email.config';
|
||||||
|
import type { EmailSendOptions, EmailTemplateSendOptions } from '@/type/email.type';
|
||||||
|
|
||||||
|
// 邮件发送Demo类
|
||||||
|
class EmailDemo {
|
||||||
|
private initialized = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化邮件服务
|
||||||
|
*/
|
||||||
|
async init(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
console.log('🚀 正在初始化邮件服务...');
|
||||||
|
|
||||||
|
// 检查配置
|
||||||
|
const isConfigValid = validateEmailConfig();
|
||||||
|
if (!isConfigValid) {
|
||||||
|
console.log('❌ 邮件配置无效,请检查环境变量配置');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化服务
|
||||||
|
await initializeEmailService();
|
||||||
|
this.initialized = true;
|
||||||
|
|
||||||
|
console.log('✅ 邮件服务初始化成功');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ 邮件服务初始化失败:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 健康检查
|
||||||
|
*/
|
||||||
|
async healthCheck(): Promise<void> {
|
||||||
|
console.log('\n🔍 执行健康检查...');
|
||||||
|
try {
|
||||||
|
const health = await checkEmailServiceHealth();
|
||||||
|
console.log(`📊 健康状态: ${health.status}`);
|
||||||
|
console.log(`⏱️ 响应时间: ${health.responseTime}ms`);
|
||||||
|
console.log(`🔗 服务状态: ${health.serviceStatus}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ 健康检查失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送简单测试邮件
|
||||||
|
*/
|
||||||
|
async sendSimpleEmail(to: string): Promise<void> {
|
||||||
|
console.log(`\n📧 发送简单测试邮件到: ${to}`);
|
||||||
|
|
||||||
|
const emailOptions: EmailSendOptions = {
|
||||||
|
to: to,
|
||||||
|
subject: '邮件服务测试 - 简单邮件',
|
||||||
|
text: '这是一封测试邮件的纯文本内容。如果您收到这封邮件,说明邮件服务工作正常!',
|
||||||
|
html: `
|
||||||
|
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||||
|
<h2 style="color: #2563eb;">🎉 邮件服务测试成功!</h2>
|
||||||
|
<p>这是一封<strong>HTML格式</strong>的测试邮件。</p>
|
||||||
|
<div style="background: #f3f4f6; padding: 20px; border-radius: 8px; margin: 20px 0;">
|
||||||
|
<p><strong>测试信息:</strong></p>
|
||||||
|
<ul>
|
||||||
|
<li>发送时间: ${new Date().toLocaleString('zh-CN')}</li>
|
||||||
|
<li>邮件类型: HTML格式</li>
|
||||||
|
<li>服务状态: 正常运行</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<p style="color: #6b7280;">如果您收到这封邮件,说明邮件发送服务配置正确!</p>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await sendEmail(emailOptions);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
console.log('✅ 邮件发送成功!');
|
||||||
|
console.log(`📮 消息ID: ${result.messageId}`);
|
||||||
|
console.log(`📬 接收方: ${result.accepted?.join(', ')}`);
|
||||||
|
} else {
|
||||||
|
console.log('❌ 邮件发送失败');
|
||||||
|
console.log(`💥 错误信息: ${result.error}`);
|
||||||
|
if (result.rejected && result.rejected.length > 0) {
|
||||||
|
console.log(`🚫 被拒绝的邮箱: ${result.rejected.join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ 发送过程中出现异常:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送模板邮件测试
|
||||||
|
*/
|
||||||
|
async sendTemplateEmail(to: string): Promise<void> {
|
||||||
|
console.log(`\n📧 发送模板邮件到: ${to}`);
|
||||||
|
|
||||||
|
const templateOptions: EmailTemplateSendOptions = {
|
||||||
|
to: to,
|
||||||
|
template: 'welcome',
|
||||||
|
params: {
|
||||||
|
username: 'demo_user',
|
||||||
|
nickname: '测试用户',
|
||||||
|
email: to,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await sendTemplateEmail(templateOptions);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
console.log('✅ 模板邮件发送成功!');
|
||||||
|
console.log(`📮 消息ID: ${result.messageId}`);
|
||||||
|
console.log(`📬 接收方: ${result.accepted?.join(', ')}`);
|
||||||
|
} else {
|
||||||
|
console.log('❌ 模板邮件发送失败');
|
||||||
|
console.log(`💥 错误信息: ${result.error}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ 发送过程中出现异常:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭服务
|
||||||
|
*/
|
||||||
|
async close(): Promise<void> {
|
||||||
|
if (this.initialized) {
|
||||||
|
await closeEmailService();
|
||||||
|
console.log('\n🔚 邮件服务已关闭');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主函数
|
||||||
|
async function main() {
|
||||||
|
console.log('='.repeat(50));
|
||||||
|
console.log('📧 邮件发送Demo - 验证邮件服务功能');
|
||||||
|
console.log('='.repeat(50));
|
||||||
|
|
||||||
|
const demo = new EmailDemo();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 初始化
|
||||||
|
const initSuccess = await demo.init();
|
||||||
|
if (!initSuccess) {
|
||||||
|
console.log('\n💡 请检查以下环境变量配置:');
|
||||||
|
console.log('- SMTP_HOST: SMTP服务器地址');
|
||||||
|
console.log('- SMTP_PORT: SMTP端口');
|
||||||
|
console.log('- SMTP_USER: 邮箱账号');
|
||||||
|
console.log('- SMTP_PASS: 邮箱密码/授权码');
|
||||||
|
console.log('- SMTP_FROM_NAME: 发件人名称');
|
||||||
|
console.log('- SMTP_FROM_EMAIL: 发件人邮箱');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 健康检查
|
||||||
|
await demo.healthCheck();
|
||||||
|
|
||||||
|
// 询问收件人邮箱
|
||||||
|
const testEmail = process.argv[2] || 'test@example.com';
|
||||||
|
console.log(`\n🎯 测试邮箱: ${testEmail}`);
|
||||||
|
|
||||||
|
if (testEmail === 'test@example.com') {
|
||||||
|
console.log('💡 提示: 可以通过参数指定邮箱地址');
|
||||||
|
console.log(' 示例: bun run src/tests/demo/emailDemo.ts your@email.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送测试邮件
|
||||||
|
await demo.sendSimpleEmail(testEmail);
|
||||||
|
|
||||||
|
// 等待一下再发送模板邮件
|
||||||
|
console.log('\n⏳ 等待2秒后发送模板邮件...');
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
|
|
||||||
|
await demo.sendTemplateEmail(testEmail);
|
||||||
|
|
||||||
|
console.log('\n' + '='.repeat(50));
|
||||||
|
console.log('✨ Demo执行完成!请检查您的邮箱收件箱');
|
||||||
|
console.log('📬 如果没收到邮件,请检查垃圾邮件文件夹');
|
||||||
|
console.log('='.repeat(50));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('💥 Demo执行过程中出现错误:', error);
|
||||||
|
} finally {
|
||||||
|
// 关闭服务
|
||||||
|
await demo.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果直接运行此文件
|
||||||
|
if (import.meta.main) {
|
||||||
|
main().catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { EmailDemo };
|
@ -25,7 +25,7 @@ import type { EmailSendOptions, EmailTemplateSendOptions } from '@/type/email.ty
|
|||||||
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
// 测试用的邮箱地址(请根据实际情况修改)
|
// 测试用的邮箱地址(请根据实际情况修改)
|
||||||
const TEST_EMAIL = 'test@example.com';
|
const TEST_EMAIL = 'x71291@outlook.com';
|
||||||
const TEST_USERNAME = 'test_user';
|
const TEST_USERNAME = 'test_user';
|
||||||
const TEST_NICKNAME = '测试用户';
|
const TEST_NICKNAME = '测试用户';
|
||||||
|
|
||||||
|
@ -198,6 +198,7 @@ export interface EmailServiceConfig {
|
|||||||
/** 邮件基础配置 */
|
/** 邮件基础配置 */
|
||||||
email: {
|
email: {
|
||||||
from: string;
|
from: string;
|
||||||
|
fromName: string;
|
||||||
replyTo: string;
|
replyTo: string;
|
||||||
charset: string;
|
charset: string;
|
||||||
priority: EmailPriority;
|
priority: EmailPriority;
|
||||||
|
Loading…
Reference in New Issue
Block a user