Files
smail/workers/app.ts
2025-06-04 21:43:57 +08:00

108 lines
2.5 KiB
TypeScript
Raw Permalink 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 PostalMime from "postal-mime";
import { createRequestHandler } from "react-router";
import {
cleanupExpiredEmails,
createDB,
getOrCreateMailbox,
storeEmail,
} from "../app/lib/db";
declare module "react-router" {
export interface AppLoadContext {
cloudflare: {
env: Env;
ctx: ExecutionContext;
};
}
}
const requestHandler = createRequestHandler(
() => import("virtual:react-router/server-build"),
import.meta.env.MODE,
);
interface ParsedEmail {
messageId?: string;
from?: {
name?: string;
address?: string;
};
to?: Array<{
name?: string;
address?: string;
}>;
subject?: string;
text?: string;
html?: string;
attachments?: Array<{
filename?: string;
mimeType?: string;
size?: number;
contentId?: string;
related?: boolean;
content?: ArrayBuffer;
}>;
}
export default {
async fetch(request, env, ctx) {
return requestHandler(request, {
cloudflare: { env, ctx },
});
},
async email(
message: ForwardableEmailMessage,
env: Env,
ctx: ExecutionContext,
): Promise<void> {
try {
console.log(
`📧 Received email: ${message.from} -> ${message.to}, size: ${message.rawSize}`,
);
// 创建数据库实例
const db = createDB();
// 清理过期邮件(异步执行,不阻塞当前邮件处理)
ctx.waitUntil(cleanupExpiredEmails(db));
// 读取原始邮件内容
const rawEmailArray = await new Response(message.raw).arrayBuffer();
const rawEmail = new TextDecoder().decode(rawEmailArray);
// 使用 postal-mime 解析邮件
const parsedEmail = (await PostalMime.parse(
rawEmailArray,
)) as ParsedEmail;
console.log(
`📝 Parsed email from: ${parsedEmail.from?.address}, subject: ${parsedEmail.subject}`,
);
// 获取或创建邮箱记录使用统一的drizzle方法
const mailbox = await getOrCreateMailbox(db, message.to);
console.log(
`📦 Found/Created mailbox: ${mailbox.id} for ${mailbox.email}`,
);
// 存储邮件到数据库,附件存储到 R2
const emailId = await storeEmail(
db,
env.ATTACHMENTS, // R2 存储桶
mailbox.id,
parsedEmail,
rawEmail,
message.rawSize,
message.to,
);
console.log(`✅ Email stored successfully with ID: ${emailId}`);
} catch (error) {
console.error("❌ Error processing email:", error);
// 在生产环境中,你可能想要拒绝邮件或发送到错误队列
// message.setReject("Email processing failed");
}
},
} satisfies ExportedHandler<Env>;