Show HN:Posthorn,无需邮件服务器的自托管邮件

2026-05-27 1 阅读 craigmccaskill
Posthorn 用于自托管项目的统一出站邮件层。您自行托管的每个应用程序与您已选择的交易邮件提供商之间的一个网关。三种入口形状(HTTP 表单、HTTP API、SMTP)、五种传输(Postmark、Resend、Mailgun、AWS SES、出站 SMTP 中继)、单个 Go 二进制文件、单个 TOML 配置。现实世界的堆栈:Hugo + Comentario · Ghost · Gitea · Umami 摘要 cron · Cloudflare Worker 为什么没有人愿意在 2026 年运行邮件服务器。自托管运营商使用 Postmark、Resend、Mailgun 或 AWS SES,因为它们便宜,可以正确处理交付能力,而其他人则担心 SPF / DKIM / DMARC / 退回邮件 / 发件人声誉。但您自行托管的每个应用程序都必须独立与该服务集成。您的联系表。您的 Ghost 博客的管理员电子邮件。您的 Gitea 魔法链接。您的乳齿象通知。当有人点击链接时,Cloudflare Worker 会触发密码重置电子邮件。每个都需要自己的 API 密钥副本、自己的集成代码、自己的重试和退回处理怪癖。同样的出站问题在您的堆栈中重复出现。在阻止出站 SMTP 的云主机上(DigitalOcean、AWS Lightsail、Linode、Vultr),如果没有解决方法,仅 SMTP 的应用程序根本无法运行。波斯特霍恩是一座桥梁。一个容器、一个配置、一组凭据。您的应用程序指向 Posthorn。 Posthorn 与您的提供商交谈。你的应用连接到哪里 Posthorn 做什么 HTTP 表单(联系表单、注册、警报 webhooks) Honeypot + Origin/Referer + 速率限制 + 可选的 CSRF;电子邮件模板;发送 HTTP API 模式(workers、cron、支付处理程序、内部服务) 授权:Bearer auth; JSON 主体;幂等重试;事务性发送 SMTP 侦听器的每个请求 to_override(Ghost、Gitea、Mastodon、Matrix、NextCloud、Authentik、任何发出 SMTP 的内容)AUTH PLAIN 或 client-cert;需要 STARTTLS;发件人 + 收件人白名单;解析 MIME;通过 HTTP API 传输转发 所有三个入口汇聚到一个传输。消息和一个出站提供商 — 从 Postmark、Resend、Mailgun、AWS SES 或出站 SMTP 中继中进行选择。 Posthorn 不是什么 为了避免您走错方向:它的作用 看看而不是邮件服务器 没有邮箱存储,没有 IMAP/JMAP,没有 DKIM 密钥管理,没有 MX 目标 Stalwart 、 Mailcow 、 iRedMail 不是自己的出站基础设施 Posthorn 通过您选择的提供商进行中继;它不运行自己的 SMTP 队列或管理 IP 声誉 Postal、Hyvor Relay 不是营销电子邮件平台 没有列表管理、没有分段、没有活动仪表板 Listmonk 不是网络邮件/邮箱 UI 没有用于阅读邮件的界面 Roundcube、Snappymail(带有邮件服务器) 楔子是您的自托管应用程序和您已选择的交易提供商之间的集成层。文档 posthorn.dev — 入门、配置参考、部署指南、功能深入研究、安全模型、HTTP API 参考、常见问题解答。十个秘诀,涵盖联系表单、时事通讯注册、多形式网站、监控警报、Cloudflare Workers、内部 SMTP 中继 (Docker Compose) 以及 Hugo+Commentario、Ghost、Gitea 和自托管 Umami 摘要的完整案例研究。有关项目历史记录和 v1.0 规范,请参阅 spec/ 。快速启动 (Docker) # docker-compose.yml 服务 : posthorn : image : ghcr.io/craigmccaskill/posthorn:latest restart : 除非停止卷 : - ./posthorn.toml:/etc/posthorn/config.toml:ro 环境 : POSTMARK_API_KEY : ${POSTMARK_API_KEY} ports : - " 127.0.0.1:8080:8080 " # 绑定到环回;来自前门的反向代理 # posthorn.toml [[ endpoints ]] path = " /api/contact " to = [ " you@example.com " ] from = " 联系表单 " honeypot = " _gotcha " allowed_origins = [ " https://example.com " ] required = [ " name " , " email " , " message " ] subject = " Contact from {{.name}} " body = """来自:{{.name}} <{{.email}}> {{.message}} """ redirect_success = " /thank-you " [ 端点 .运输]类型=“邮戳”[端点。运输 。设置] api_key =“${env.POSTMARK_API_KEY}”[端点。 rate_limit] count = 5 Interval = " 1m " 从您的前门(Caddy、nginx、Traefik)反向代理 /api/contact 到 http://posthorn:8080 。将表单的操作指向 /api/contact 。完毕。完整演练:posthorn.dev/getting-started/quick-start 。 API 模式(服务器到服务器) 对于 Workers、cron 作业、内部服务 — 任何使用 JSON 而不是表单的内容: [[ endpoints ]] path = " /api/transactional " to = [ "fallback@yourdomain.com " ] from = " YourApp " auth = " api-key " api_keys = [ " ${env.WORKER_KEY_PRIMARY} " , " ${env.WORKER_KEY_BACKUP} "] 必需 = [" subject_line ", " message " ] subject = " {{.subject_line}} " body = " {{.message}} " [ 端点 .运输]类型=“邮戳”[端点。运输 。设置] api_key =“${env.POSTMARK_API_KEY}”curl -X POST https://posthorn.yourdomain.com/ap