使用 Worker Mailer 在 Cloudflare Workers 中通过 SSL 发送电子邮件

简介

在 Cloudflare Workers 中发送电子邮件一直是一个挑战。传统的方法通常依赖于 HTTP 邮件 API(如 Resend、SendGrid、MailChannels),但这些服务可能有使用限制或需要额外付费。

现在,有了 worker-mailer,我们可以直接在 Cloudflare Workers 中使用 SMTP 通过 SSL/TLS 发送邮件,而不需要依赖任何第三方 HTTP API。它利用了 Cloudflare 的 TCP Sockets API,实现了真正的端到端加密邮件发送。

为什么选择 Worker Mailer

与传统方法的对比

方法 优势 劣势
HTTP API (Resend/SendGrid) 设置简单,文档完善 需要付费,有发送限制
MailChannels 免费,无需配置 DNS 配置复杂,限制较多
Cloudflare Email Service 原生集成 需要 Pro 计划,发送受限
Worker Mailer 完全免费,无限制,SSL 加密 需要配置 SMTP 服务器

Worker Mailer 的特点

  • 🚀 零依赖:完全基于 Cloudflare Workers 运行时
  • 🔒 SSL/TLS 加密:支持隐式 TLS(端口 465)和 STARTTLS(端口 587)
  • 📧 支持富文本邮件:HTML 和纯文本邮件,支持附件
  • 多种认证方式:支持 plainloginCRAM-MD5
  • 📝 完整的 TypeScript 支持:类型安全的 API

安装与配置

步骤 1:创建 Worker 项目

1
2
npm create cloudflare@latest -- worker-mailer-demo
cd worker-mailer-demo

步骤 2:安装 Worker Mailer

1
npm install @ribassu/worker-mailer

步骤 3:配置 wrangler.toml

需要启用 nodejs_compat 兼容性标志:

1
2
3
4
5
6
7
8
9
name = "worker-mailer-demo"
main = "src/index.ts"
compatibility_date = "2025-07-09"
compatibility_flags = ["nodejs_compat"]

[vars]
SMTP_HOST = "smtp.example.com"
SMTP_PORT = "465"
SMTP_USERNAME = "[email protected]"

步骤 4:设置密码为 Secret

1
wrangler secret put SMTP_PASSWORD

基本使用示例

发送纯文本邮件

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
import { WorkerMailer } from '@ribassu/worker-mailer'

interface Env {
SMTP_HOST: string
SMTP_PORT: string
SMTP_USERNAME: string
SMTP_PASSWORD: string
}

export default {
async fetch(request: Request, env: Env): Promise<Response> {
const mailer = await WorkerMailer.connect({
credentials: {
username: env.SMTP_USERNAME,
password: env.SMTP_PASSWORD,
},
authType: 'plain',
host: env.SMTP_HOST,
port: parseInt(env.SMTP_PORT),
secure: true,
})

await mailer.send({
from: { name: 'WTSolutions', email: env.SMTP_USERNAME },
to: { name: 'Recipient', email: '[email protected]' },
subject: 'Hello from Worker Mailer',
text: '这是一封通过 Cloudflare Workers 发送的邮件!',
})

return new Response('邮件发送成功!')
},
} satisfies ExportedHandler<Env>

发送 HTML 邮件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
await mailer.send({
from: { name: 'WTSolutions', email: env.SMTP_USERNAME },
to: { name: 'Recipient', email: '[email protected]' },
subject: '欢迎使用我们的服务',
text: '欢迎使用我们的服务!请点击下方链接开始。',
html: `
<div style="font-family: sans-serif; padding: 20px;">
<h1>欢迎!</h1>
<p>感谢您注册我们的服务。</p>
<a href="https://wtsolutions.cn" style="display: inline-block; padding: 10px 20px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px;">
立即开始
</a>
</div>
`,
})

发送带附件的邮件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const attachment = {
filename: 'document.pdf',
content: pdfBuffer,
contentType: 'application/pdf',
}

await mailer.send({
from: { name: 'WTSolutions', email: env.SMTP_USERNAME },
to: { name: 'Recipient', email: '[email protected]' },
subject: '您的文档',
text: '请查收附件中的文档。',
html: '<p>请查收附件中的文档。</p>',
attachments: [attachment],
})

支持的 SMTP 服务提供商配置

Gmail / Google Workspace

1
2
SMTP_HOST = "smtp.gmail.com"
SMTP_PORT = "465"

注意:需要使用 App Password,而不是账户密码。

Outlook / Office 365

1
2
SMTP_HOST = "smtp.office365.com"
SMTP_PORT = "587"

163 邮箱

1
2
SMTP_HOST = "smtp.163.com"
SMTP_PORT = "465"

QQ 邮箱

1
2
SMTP_HOST = "smtp.qq.com"
SMTP_PORT = "465"

Cloudflare Email Service (SMTP)

Cloudflare 最近发布了 SMTP 提交支持:

1
2
SMTP_HOST = "smtp.mx.cloudflare.net"
SMTP_PORT = "465"

使用 Cloudflare API Token 作为密码。

高级配置选项

STARTTLS 模式

对于端口 587,使用 STARTTLS:

1
2
3
4
5
6
7
8
9
10
11
const mailer = await WorkerMailer.connect({
credentials: {
username: env.SMTP_USERNAME,
password: env.SMTP_PASSWORD,
},
authType: 'login',
host: env.SMTP_HOST,
port: 587,
secure: false,
startTls: true,
})

生命周期钩子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const mailer = await WorkerMailer.connect({
credentials: {
username: env.SMTP_USERNAME,
password: env.SMTP_PASSWORD,
},
host: env.SMTP_HOST,
port: 465,
secure: true,
hooks: {
onConnect: () => console.log('Connected to SMTP server'),
onAuthenticate: () => console.log('Authenticated successfully'),
onSend: (message) => console.log(`Sent email to ${message.to.email}`),
onError: (error) => console.error('Error:', error),
},
})

超时配置

1
2
3
4
5
6
7
8
9
10
11
const mailer = await WorkerMailer.connect({
credentials: {
username: env.SMTP_USERNAME,
password: env.SMTP_PASSWORD,
},
host: env.SMTP_HOST,
port: 465,
secure: true,
socketTimeoutMs: 30000,
responseTimeoutMs: 10000,
})

Cloudflare Workers 限制说明

端口限制

Cloudflare Workers 不允许使用端口 25(SMTP 默认端口),这是为了防止垃圾邮件。必须使用:

  • 端口 465:隐式 TLS(推荐)
  • 端口 587:STARTTLS

TCP Sockets 权限

确保你的 Worker 具有 connect() 权限。在 wrangler.toml 中配置:

1
compatibility_date = "2025-07-09"

完整示例:联系表单处理

以下是一个完整的示例,处理来自前端的联系表单请求并发送邮件:

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
import { WorkerMailer } from '@ribassu/worker-mailer'

interface Env {
SMTP_HOST: string
SMTP_PORT: string
SMTP_USERNAME: string
SMTP_PASSWORD: string
}

interface ContactForm {
name: string
email: string
subject: string
message: string
}

export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 })
}

try {
const form: ContactForm = await request.json()

const mailer = await WorkerMailer.connect({
credentials: {
username: env.SMTP_USERNAME,
password: env.SMTP_PASSWORD,
},
authType: 'plain',
host: env.SMTP_HOST,
port: parseInt(env.SMTP_PORT),
secure: true,
})

await mailer.send({
from: { name: form.name, email: form.email },
to: { name: 'Admin', email: env.SMTP_USERNAME },
replyTo: { email: form.email },
subject: `Contact Form: ${form.subject}`,
text: `
Name: ${form.name}
Email: ${form.email}
Subject: ${form.subject}
Message: ${form.message}
`,
html: `
<h2>新的联系表单提交</h2>
<p><strong>姓名:</strong> ${form.name}</p>
<p><strong>邮箱:</strong> ${form.email}</p>
<p><strong>主题:</strong> ${form.subject}</p>
<p><strong>消息:</strong></p>
<p>${form.message}</p>
`,
})

return Response.json({ success: true, message: '邮件发送成功' })
} catch (error) {
console.error('发送邮件失败:', error)
return Response.json(
{ success: false, message: '发送邮件失败' },
{ status: 500 }
)
}
},
} satisfies ExportedHandler<Env>

部署

1
wrangler deploy

测试

使用 curl 测试:

1
2
3
4
5
6
7
8
curl -X POST https://worker-mailer-demo.your-subdomain.workers.dev \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "[email protected]",
"subject": "Test Email",
"message": "This is a test email sent via Worker Mailer."
}'

总结

@ribassu/worker-mailer 为 Cloudflare Workers 提供了一种全新的邮件发送方式:

  1. 不依赖 HTTP API:直接通过 TCP Sockets 连接 SMTP 服务器
  2. 完全免费:没有发送限制,只受 Cloudflare Workers 免费额度限制
  3. SSL/TLS 加密:确保邮件传输安全
  4. 灵活配置:支持多种 SMTP 服务提供商和认证方式

如果你正在寻找一种在 Cloudflare Workers 中发送邮件的可靠方案,Worker Mailer 是一个非常好的选择。