11
This commit is contained in:
189
api/services/email_service.js
Normal file
189
api/services/email_service.js
Normal file
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* 邮件服务
|
||||
* 使用QQ邮箱SMTP服务发送邮件
|
||||
*/
|
||||
|
||||
const nodemailer = require('nodemailer');
|
||||
const config = require('../../config/config.js');
|
||||
|
||||
// 创建邮件传输器
|
||||
let transporter = null;
|
||||
|
||||
/**
|
||||
* 初始化邮件传输器
|
||||
*/
|
||||
function init_transporter() {
|
||||
if (transporter) {
|
||||
return transporter;
|
||||
}
|
||||
|
||||
// QQ邮箱SMTP配置
|
||||
const email_config = config.email || {
|
||||
host: 'smtp.qq.com',
|
||||
port: 465,
|
||||
secure: true, // 使用SSL
|
||||
auth: {
|
||||
user: process.env.QQ_EMAIL_USER || '', // QQ邮箱账号
|
||||
pass: process.env.QQ_EMAIL_PASS || '' // QQ邮箱授权码(不是密码)
|
||||
}
|
||||
};
|
||||
|
||||
transporter = nodemailer.createTransport({
|
||||
host: email_config.host,
|
||||
port: email_config.port,
|
||||
secure: email_config.secure,
|
||||
auth: email_config.auth
|
||||
});
|
||||
|
||||
return transporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
* @param {Object} options 邮件选项
|
||||
* @param {string} options.to 收件人邮箱
|
||||
* @param {string} options.subject 邮件主题
|
||||
* @param {string} options.html 邮件HTML内容
|
||||
* @param {string} options.text 邮件纯文本内容(可选)
|
||||
* @returns {Promise<{success: boolean, message?: string, messageId?: string}>}
|
||||
*/
|
||||
async function send_email(options) {
|
||||
try {
|
||||
const transporter_instance = init_transporter();
|
||||
|
||||
if (!transporter_instance) {
|
||||
return {
|
||||
success: false,
|
||||
message: '邮件服务未配置'
|
||||
};
|
||||
}
|
||||
|
||||
// 如果没有配置邮箱账号,返回错误
|
||||
const email_config = config.email || {};
|
||||
if (!email_config.auth || !email_config.auth.user || !email_config.auth.pass) {
|
||||
console.warn('[邮件服务] QQ邮箱未配置,使用模拟发送');
|
||||
// 开发环境可以模拟发送
|
||||
if (config.env === 'development') {
|
||||
console.log(`[模拟邮件] 发送到 ${options.to}`);
|
||||
console.log(`[模拟邮件] 主题: ${options.subject}`);
|
||||
console.log(`[模拟邮件] 内容: ${options.text || options.html}`);
|
||||
return {
|
||||
success: true,
|
||||
message: '邮件已发送(模拟)',
|
||||
messageId: 'mock-' + Date.now()
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: '邮件服务未配置,请联系管理员'
|
||||
};
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
const mail_options = {
|
||||
from: `"${email_config.fromName || '自动找工作系统'}" <${email_config.auth.user}>`,
|
||||
to: options.to,
|
||||
subject: options.subject,
|
||||
html: options.html,
|
||||
text: options.text || options.html.replace(/<[^>]*>/g, '') // 如果没有text,从html提取
|
||||
};
|
||||
|
||||
const info = await transporter_instance.sendMail(mail_options);
|
||||
|
||||
console.log(`[邮件服务] 邮件发送成功: ${options.to}, MessageId: ${info.messageId}`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: '邮件发送成功',
|
||||
messageId: info.messageId
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[邮件服务] 发送邮件失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: error.message || '发送邮件失败'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码邮件
|
||||
* @param {string} email 收件人邮箱
|
||||
* @param {string} code 验证码
|
||||
* @returns {Promise<{success: boolean, message?: string, messageId?: string}>}
|
||||
*/
|
||||
async function send_verification_code(email, code) {
|
||||
const subject = '【自动找工作系统】注册验证码';
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.content {
|
||||
background: #ffffff;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
.code-box {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 8px;
|
||||
}
|
||||
.tip {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<h2>验证码</h2>
|
||||
<p>您好,</p>
|
||||
<p>您正在注册自动找工作系统,验证码为:</p>
|
||||
<div class="code-box">${code}</div>
|
||||
<p>验证码有效期为 <strong>5分钟</strong>,请勿泄露给他人。</p>
|
||||
<div class="tip">
|
||||
<p>如果这不是您的操作,请忽略此邮件。</p>
|
||||
<p>此邮件由系统自动发送,请勿回复。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
return await send_email({
|
||||
to: email,
|
||||
subject: subject,
|
||||
html: html
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
send_email,
|
||||
send_verification_code,
|
||||
init_transporter
|
||||
};
|
||||
Reference in New Issue
Block a user