- SignalDeskyesterday
Original Summary
一、 系统架构 零服务器成本:纯 Serverless 架构,完全基于 Cloudflare 免费套餐(Email Routing + Worker + D1 数据库),不需要租用任何 VPS。 多渠道自动分流:开启 Catch-all 规则,任意前缀(如 gmail@yourdomain.com 、outlook-work@yourdomain.com)随时可用,自动标记渠道。 毫秒级双重响应: Telegram 手机秒弹:来信 1~2 秒内推送到手机,链接原生高亮可点。( 目前测试响应挺快的 ) D1 终身归档备份:SQLite 数据库持久化存储,支持 SQL 检索。( CF只有5G的免费空间,有大容量附件的建议设置定时保存,我只是用来接验证码和工作日报完全够用 ) 专业渲染 HTML 日报与账单:内置 Base64 / Quoted-Printable 深度解码引擎,Python 生成的复杂 HTML 报表、银行对账单在 Web 端原汁原味 1:1 渲染。 密码保护独立面板:绑定自定义二级域名( mail.yourdomain.com ),带密码保护的响应式邮箱看板。 二、 前置准备条件 Cloudflare 账号 一个托管在 Cloudflare 上的自定义域名(本教程以 yourdomain.com 为例)。 TG机器人(需要用到bot token和个人id) 在 TG 找 @BotFather 发送 /newbot 获取 TG_BOT_TOKEN。 在 TG 找个可以获取自己的纯数字的机器人即可获取 TG_CHAT_ID。 务必在 TG 找到自己刚建的机器人,点击一次 Start 激活对话。 三、 全流程搭建步骤 1、开启 Cloudflare 邮件路由(Email Routing) 直接把你的域名添加到看板确定就可以了 2、创建 D1 数据库并初始化表结构 点击左侧主菜单 Storage & Databases(存储和数据库) → D1 SQL Database。 点击 Create Database(创建数据库),名称写个自己喜欢的。 创建完成后,点击进入 mail_db,切换到 Console(控制台) 选项卡。( 这里主要是创建收件的表结构,有特殊需求可以自行修改 ) 粘贴并执行以下建表 SQL: CREATE TABLE emails ( id INTEGER PRIMARY KEY AUTOINCREMENT, message_from TEXT, message_to TEXT, subject TEXT, body_text TEXT, body_html TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); 3、创建一体化 Worker(收信 + 看板 + TG 推送) 新建 Worker 访问左侧菜单 Compute → Workers & Pages → 点击 Create → 选择 Worker。 这里我当时是选择了‘Hello World!’这个,如果有大佬开源的Worker用来收邮件也可以去github上找?(我没去找过QAQ) 命名为:mail-receiver( 随便起名 ),点击右下角 Deploy(部署)。 贴入完整核心代码 点击右上方的Edit code,清空原有内容,将以下代码粘贴进去:( 这里只是给个参考,可以让ai给你一个更适合你个人需求的代码 ) export default { // ================= 1. 邮件处理核心 (防重试 + 解码 + 入库 + TG) ================= async email(message, env, ctx) { try { const fromRaw = message.headers.get('from') || message.from; const toRaw = message.to; const subjectRaw = message.headers.get('subject') || '(无主题)'; // 解码中文发件人与标题 (RFC 2047) const from = decodeHeader(fromRaw); const subject = decodeHeader(subjectRaw); const prefix = toRaw.split('@')[0].toUpperCase(); // 解析文本和 HTML 正文 (支持 QP 和 Base64 深度解码) let cleanText = ''; let cleanHtml = ''; try { const rawText = await new Response(message.raw).text(); const parsed = parseMime(rawText); cleanText = parsed.text; cleanHtml = parsed.html; } catch (e) { cleanText = '(正文解析失败)'; } // 写入 D1 数据库 try { await env.DB.prepare(
INSERT INTO emails (message_from, message_to, subject, body_text, body_html) VALUES (?, ?, ?, ?, ?)).bind(from, toRaw, subject, cleanText, cleanHtml).run(); } catch (err) { console.error('写入数据库失败:', err); } // 推送到 Telegram (纯文本原生模式:零转义、绝不报错、链接原生高亮可点) if (env.TG_BOT_TOKEN && env.TG_CHAT_ID) { const preview = cleanText.slice(0, 800) + (cleanText.length > 800 ? '\n...(内容过长,请到网页端查看完整版)' : ''); const tgText =🔔 [${prefix} 渠道来信]\n\n+👤 发件人: ${from}\n+📌 主 题: ${subject}\n+📥 收件箱: ${toRaw}\n\n+📝 文本预览:\n${preview}; try { await fetch(https://api.telegram.org/bot${env.TG_BOT_TOKEN}/sendMessage, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chat_id: env.TG_CHAT_ID, text: tgText, disable_web_page_preview: false }) }); } catch (err) {} } } catch (globalErr) { console.error('邮件处理未知异常:', globalErr); } // 关键:明确返回,告知邮件服务器已接收,杜绝 451 循环重发 return; }, // ================= 2. 网页端服务 (支持密码验证与 HTML 日报沙箱) ================= async fetch(request, env, ctx) { const url = new URL(request.url); const cookies = request.headers.get('Cookie') || ''; const isAuthed = cookies.includes(auth=${env.WEB_PASSWORD}); // 处理登录 if (url.pathname === '/login' && request.method === 'POST') { const formData = await request.formData(); if (formData.get('pwd') === env.WEB_PASSWORD) { return new Response('', { status: 302, headers: { 'Location': '/', 'Set-Cookie':auth=${env.WEB_PASSWORD}; Path=/; HttpOnly; Max-Age=2592000; SameSite=Lax} }); } return new Response('密码错误!<a href="https://linux.do/">返回</a>', { headers: { 'Content-Type': 'text/html;charset=utf-8' } }); } // 未登录拦截 if (!isAuthed && env.WEB_PASSWORD) { return new Response(renderLoginPage(), { headers: { 'Content-Type': 'text/html;charset=utf-8' } }); } // 独立提供 HTML 视窗(供 iframe 沙箱隔离渲染) if (url.pathname === '/render-html') { const id = url.searchParams.get('id'); const row = await env.DB.prepare('SELECT body_html, body_text FROM emails WHERE id = ?').bind(id).first(); if (!row) return new Response('未找到该邮件'); return new Response(row.body_html ||<pre >${row.body_text}</pre>, { headers: { 'Content-Type': 'text/html;charset=utf-8' } }); } // 主邮箱看板 const list = await env.DB.prepare('SELECT id, message_from, message_to, subject, created_at FROM emails ORDER BY id DESC LIMIT 50').all(); const activeId = url.searchParams.get('id') || (list.results[0] ? list.results[0].id : null); let activeMail = null; if (activeId) { activeMail = await env.DB.prepare('SELECT FROM emails WHERE id = ?').bind(activeId).first(); } return new Response(renderMailboxPage(list.results, activeMail), { headers: { 'Content-Type': 'text/html;charset=utf-8' } }); } }; // ================= 辅助工具:MIME 解码引擎 ================= function parseMime(raw) { let text = ''; let html = ''; const boundaryMatch = raw.match(/boundary="?([^";\r\n]+)"?/i); if (boundaryMatch) { const boundary = boundaryMatch[1]; const parts = raw.split('--' + boundary); for (const part of parts) { if (/content-type:\stext\/html/i.test(part)) { html = extractBodyPart(part); } else if (/content-type:\stext\/plain/i.test(part)) { text = extractBodyPart(part); } } } else { if (/content-type:\stext\/html/i.test(raw)) { html = extractBodyPart(raw); } else { text = extractBodyPart(raw); } } return { text: text || '(纯 HTML 邮件)', html: html || '' }; } function extractBodyPart(part) { const chunks = part.split(/\r?\n\r?\n/); if (chunks.length < 2) return ''; const header = chunks[0]; let body = chunks.slice(1).join('\n\n').replace(/--$/, '').trim(); // 1. Base64 编码解码 if (/content-transfer-encoding:\s*base64/i.test(header)) { try { const bin = atob(body.replace(/\s/g, '')); const bytes = Uint8Array.from(bin, c => c.charCodeAt(0)); return new TextDecoder('utf-8').decode(byte- 情报分类:工作与职业机会
- 分类依据:内容涉及招聘、求职或职业发展
- 信息来源:服务器 / LINUX DO - 最新话题
- 发布时间:2026/9/17 21:55:25
- No replies yet