-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcloudflare-worker.js
More file actions
150 lines (130 loc) · 4.62 KB
/
cloudflare-worker.js
File metadata and controls
150 lines (130 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
* Cloudflare Email Worker
* 接收邮件并转发到你的 Web 应用
*
* 部署方式:
* 1. 在 Cloudflare Dashboard 创建一个 Worker
* 2. 复制此代码到 Worker 编辑器
* 3. 在 Email Routing 中将邮件路由到此 Worker
* 4. 配置环境变量(可选)
*/
export default {
// 处理 HTTP 请求(用于健康检查和测试)
async fetch(request, env, ctx) {
const url = new URL(request.url);
// 健康检查端点
if (url.pathname === '/health') {
return new Response(JSON.stringify({
status: 'ok',
message: 'Email Worker is running',
timestamp: new Date().toISOString(),
}), {
headers: { 'Content-Type': 'application/json' },
});
}
// 测试邮件转发端点
if (url.pathname === '/test' && request.method === 'POST') {
try {
const testEmail = await request.json();
const WEB_APP_URL = env.WEB_APP_URL || 'http://your-server-ip:3303';
const API_KEY = env.WEBHOOK_API_KEY || '';
const response = await fetch(`${WEB_APP_URL}/api/webhook/email`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
},
body: JSON.stringify(testEmail),
});
const result = await response.json();
return new Response(JSON.stringify({
success: true,
webAppResponse: result,
}), {
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
return new Response(JSON.stringify({
success: false,
error: error.message,
}), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}
// 默认响应
return new Response(JSON.stringify({
message: 'Email Worker',
endpoints: {
health: '/health - Check worker status',
test: '/test - POST to test email forwarding',
},
}), {
headers: { 'Content-Type': 'application/json' },
});
},
// 处理邮件(Cloudflare Email Routing)
async email(message, env, ctx) {
try {
// 你的 Web 应用地址(建议从环境变量读取)
const WEB_APP_URL = env.WEB_APP_URL || 'http://your-server-ip:3303';
// API 密钥(必须与 Web 应用的 WEBHOOK_API_KEY 保持一致)
// 在 Worker Settings → Variables 中设置 WEBHOOK_API_KEY
const API_KEY = env.WEBHOOK_API_KEY || 'your-webhook-api-key-here';
console.log('📧 Receiving email from:', message.from, 'to:', message.to);
console.log('🔗 Forwarding to:', WEB_APP_URL);
console.log('🔑 Using API Key:', API_KEY ? API_KEY.substring(0, 20) + '...' : 'NONE');
// 读取原始邮件内容 - 使用 message.rawSize 和 ReadableStream
const rawEmailStream = message.raw;
const rawEmail = await streamToArrayBuffer(rawEmailStream);
// 转发到你的 Web 应用
const response = await fetch(`${WEB_APP_URL}/api/webhook/email`, {
method: 'POST',
headers: {
'Content-Type': 'message/rfc822',
'X-API-Key': API_KEY,
},
body: rawEmail,
});
if (response.ok) {
const result = await response.json();
console.log('✅ Email forwarded successfully:', result);
// 标记为已处理,不继续传递
message.setReject('Email processed and forwarded to web app');
} else {
const errorText = await response.text();
console.error('❌ Failed to forward email');
console.error(' Status:', response.status);
console.error(' Response:', errorText);
console.error(' Headers:', JSON.stringify([...response.headers.entries()]));
// 转发失败,可以选择拒绝或继续传递
message.setReject(`Failed to forward: ${response.status}`);
}
} catch (error) {
console.error('❌ Error processing email:', error);
message.setReject(`Error: ${error.message}`);
}
},
};
/**
* 将 ReadableStream 转换为 ArrayBuffer
*/
async function streamToArrayBuffer(stream) {
const reader = stream.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
// 合并所有 chunks
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
const result = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
result.set(chunk, offset);
offset += chunk.length;
}
return result;
}