cloudflare-chat/src/lib/email.ts

173 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Resend } from "resend";
import type { Env } from "../env";
/**
* 发送密码重置邮件
* @param env 环境变量
* @param to 收件人邮箱
* @param resetToken 重置令牌
* @param username 用户名
* @returns 发送结果
*/
export async function sendPasswordResetEmail(
env: Env,
to: string,
resetToken: string,
username: string
): Promise<{ success: boolean; error?: string }> {
const apiKey = env.RESEND_API_KEY;
const fromEmail = env.RESEND_FROM_EMAIL || "noreply@yourdomain.com";
if (!apiKey) {
return {
success: false,
error: "RESEND_API_KEY 未配置,请运行: npx wrangler secret put RESEND_API_KEY",
};
}
try {
const resend = new Resend(apiKey);
// 发送邮件
const { data, error } = await resend.emails.send({
from: fromEmail,
to: [to],
subject: "密码重置验证码 - 聊天室",
html: `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.container {
background-color: #f9f9f9;
border-radius: 8px;
padding: 30px;
border: 1px solid #e0e0e0;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.header h1 {
color: #2c3e50;
margin: 0;
}
.content {
background-color: white;
padding: 25px;
border-radius: 6px;
margin-bottom: 20px;
}
.code-box {
background-color: #f8f9fa;
border: 2px dashed #007bff;
border-radius: 8px;
padding: 20px;
margin: 25px 0;
text-align: center;
}
.verification-code {
font-size: 32px;
font-weight: bold;
color: #007bff;
letter-spacing: 4px;
font-family: 'Courier New', monospace;
user-select: all;
}
.footer {
text-align: center;
color: #666;
font-size: 14px;
margin-top: 20px;
}
.warning {
background-color: #fff3cd;
border-left: 4px solid #ffc107;
padding: 12px;
margin: 15px 0;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔐 密码重置验证码</h1>
</div>
<div class="content">
<p>你好,<strong>${username}</strong></p>
<p>我们收到了你的密码重置请求。请使用以下验证码来重置你的密码:</p>
<div class="code-box">
<div style="color: #666; font-size: 14px; margin-bottom: 10px;">验证码</div>
<div class="verification-code">${resetToken}</div>
</div>
<p style="text-align: center; color: #666; font-size: 14px;">
请在密码重置页面输入此验证码
</p>
<div class="warning">
<strong>⚠️ 重要提示:</strong>
<ul style="margin: 10px 0;">
<li>此验证码将在 <strong>30 分钟</strong>后失效</li>
<li>如果你没有请求重置密码,请忽略此邮件</li>
<li>请勿将此验证码分享给他人</li>
</ul>
</div>
</div>
<div class="footer">
<p>此邮件由系统自动发送,请勿回复。</p>
<p style="color: #999; font-size: 12px;">© 2026 聊天室应用</p>
</div>
</div>
</body>
</html>
`,
text: `
你好,${username}
我们收到了你的密码重置请求。请使用以下验证码来重置你的密码:
验证码:${resetToken}
重要提示:
- 此验证码将在 30 分钟后失效
- 如果你没有请求重置密码,请忽略此邮件
- 请勿将此验证码分享给他人
此邮件由系统自动发送,请勿回复。
`.trim(),
});
if (error) {
console.error("Resend 发送邮件失败:", error);
return {
success: false,
error: error.message || "邮件发送失败",
};
}
console.log("密码重置邮件已发送:", data);
return { success: true };
} catch (error) {
console.error("发送邮件时出错:", error);
return {
success: false,
error: error instanceof Error ? error.message : "未知错误",
};
}
}