收藏收藏
Mark
1 个赞
蛙趣,爬爬虾!
6 个赞
感动的教程!!
2 个赞
找claude糊了一个简单的发邮件页面,可以放到cloudflare的pages
lgeger/sendemail (github.com)
5 个赞
感谢分享
1 个赞
我还关注你抖音了
1 个赞
原来还能实现发邮件啊
5 个赞
这个汇总不错, 里面有一些曾经用过
1 个赞
mk
5 个赞
之前我也是用的cf,现在换成Fastmail了,可以收发邮件,除了收费别的都还不错。
2 个赞
感谢分享
3 个赞
好东西感谢分享
5 个赞
UI+邮件可添加附件,复制粘贴部署到worker,有需要拿去用,提供了简单的UI,可自行找GPT美化下。
配置两个环境变量:MY_REND_API_KEY=re_PmasB2d******
用于验证发件人密钥:SECRET_API_KEY=666666
------感谢楼主提供的完美教程------
worker.js
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
if (request.method === 'POST' && url.pathname === '/send') {
return handleSendEmail(request);
} else if (request.method === 'GET' && url.pathname === '/') {
return new Response(generateHTML(), {
headers: { 'Content-Type': 'text/html' }
});
}
return new Response('Invalid request method or path.', { status: 405 });
}
async function handleSendEmail(request) {
try {
const formData = await request.formData();
const providedApiKey = formData.get('secret_key');
if (providedApiKey !== SECRET_API_KEY) {
return new Response('Unauthorized', { status: 401 });
}
const sender = formData.get('from');
const recipient = formData.get('to');
const subject = formData.get('subject');
const content = formData.get('content');
const file = formData.get('attachment');
const emailParams = {
from: sender,
to: [recipient],
subject: subject,
html: content
};
if (file && file.size > 0) {
// 限制文件大小为 50MB
const maxSize = 50 * 1024 * 1024; // 50MB in bytes
if (file.size > maxSize) {
return new Response('File size exceeds the 50MB limit.', { status: 400 });
}
// 使用 ReadableStream 来处理文件
const fileStream = file.stream();
const reader = fileStream.getReader();
let chunks = [];
let bytesRead = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
bytesRead += value.length;
// 每读取 5MB 数据就让出控制权,避免阻塞太长时间
if (bytesRead % (5 * 1024 * 1024) === 0) {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
const fileContent = new Uint8Array(bytesRead);
let offset = 0;
for (const chunk of chunks) {
fileContent.set(chunk, offset);
offset += chunk.length;
}
emailParams.attachments = [
{
filename: file.name,
content: arrayBufferToBase64(fileContent),
type: file.type
}
];
}
const response = await fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
'Authorization': `Bearer ${MY_REND_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(emailParams)
});
if (response.ok) {
return new Response('Email sent successfully!', { status: 200 });
} else {
const errorText = await response.text();
return new Response(`Failed to send email: ${errorText}`, { status: 500 });
}
} catch (error) {
return new Response(`Error processing request: ${error.message}`, { status: 500 });
}
}
// Helper function to convert ArrayBuffer to Base64
function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
let binary = '';
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
function generateHTML() {
return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>发送邮件(可选附件,最大50MB)</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
padding: 20px;
max-width: 600px;
margin: auto;
}
form {
background: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
input, textarea {
width: 100%;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
border: 1px solid #ccc;
}
button {
padding: 10px 20px;
background-color: #28a745;
border: none;
border-radius: 5px;
color: #fff;
cursor: pointer;
}
button:hover {
background-color: #218838;
}
.progress {
width: 100%;
background-color: #f4f4f4;
border-radius: 5px;
overflow: hidden;
margin-top: 10px;
display: none;
}
.progress-bar {
height: 20px;
background-color: #28a745;
width: 0;
transition: width 0.4s;
}
.progress-text {
text-align: center;
margin-top: 10px;
font-size: 14px;
color: #666;
}
</style>
</head>
<body>
<h2>发送邮件(可选附件,最大50MB)</h2>
<form id="emailForm" action="/send" method="POST" enctype="multipart/form-data">
<label for="secret_key">密钥:</label>
<input type="password" id="secret_key" name="secret_key" required>
<label for="from">发件人:</label>
<input type="email" id="from" name="from" required>
<label for="to">收件人:</label>
<input type="email" id="to" name="to" required>
<label for="subject">主题:</label>
<input type="text" id="subject" name="subject" required>
<label for="content">内容:</label>
<textarea id="content" name="content" rows="6" required></textarea>
<label for="attachment">附件 (可选,最大50MB):</label>
<input type="file" id="attachment" name="attachment">
<button type="submit">发送邮件</button>
</form>
<div class="progress">
<div class="progress-bar" id="progress-bar"></div>
</div>
<div class="progress-text" id="progress-text"></div>
<script>
const form = document.getElementById('emailForm');
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
const progressDiv = document.querySelector('.progress');
const attachmentInput = document.getElementById('attachment');
attachmentInput.addEventListener('change', function(event) {
const file = event.target.files[0];
if (file && file.size > 50 * 1024 * 1024) {
alert('文件大小超过50MB限制,请选择较小的文件。');
event.target.value = '';
}
});
form.addEventListener('submit', function(event) {
event.preventDefault();
const formData = new FormData(form);
const xhr = new XMLHttpRequest();
xhr.open('POST', '/send', true);
progressDiv.style.display = 'block';
progressText.textContent = '准备发送...';
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
const percentComplete = (e.loaded / e.total) * 100;
progressBar.style.width = percentComplete + '%';
progressText.textContent = \`上传中... (\${Math.round(percentComplete)}%)\`;
}
};
xhr.onload = function() {
if (xhr.status === 200) {
progressText.textContent = '邮件发送成功!';
} else {
progressText.textContent = '发送邮件失败:' + xhr.responseText;
}
};
xhr.onerror = function() {
progressText.textContent = '发送请求时出错。请检查网络连接并重试。';
};
xhr.send(formData);
});
</script>
</body>
</html>
`;
}
6 个赞
感谢分享,已收藏
14 个赞
不能直接用google的邮箱来回复或者发送邮件吗?用这个resend的api
4 个赞
有教程,网上搜索一下。我设置过,但回复,直接进垃圾桶了。
那好像没用啊,进入垃圾桶的话就没意义了,回复等于没回复了
感谢分享,正好用得到
感谢分享。
貌似没法无限多企业邮箱吧,只能一个域名一个企业邮箱吧。一个域名下不同的用户名恐怕不会被视为不同的企业邮箱?