OpenMail
为人工智能时代构建的开源Customer.io替代品
Self-host您的整个客户生命周期电子邮件平台-具有完整的API、原生SDK、用于AI代理的原生MCP服务器,并且没有一次性定价。
 ](https://github.com/ShadowWalker2014/openmail/stargazers)   
快速开始 · 软件开发工具包 · API文件 · MCP服务器 · 企业 · 贡献
______________________________________________________________________
为什么选择OpenMail?
客户.io成本 每月1000美元以上 对于成长中的团队,有 API有限 这阻碍了自动化,以及 不支持AI代理OpenMail为您提供一切-自托管、完全API访问、本机SDK和本机 MCP服务器 因此,您的AI代理可以自主运行电子邮件活动。
| 功能 | OpenMail | 客户.io |
|---|---|---|
| 自托管 | ✅ | ❌ |
| 完整REST API | ✅ 一切 | ⚠️ 有限 |
| 原生SDK | ✅ 节点/浏览器/反应/Next.js | ⚠️ 仅限基本 |
| 用于AI代理的MCP服务器 | ✅ 本地 | ❌ |
| PostHog/Segment兼容 | ✅ 加入 | ❌ |
| 多工作空间 | ✅ | ✅ |
| 事件触发的活动 | ✅ | ✅ |
| 广播 | ✅ | ✅ |
| 联系人细分 | ✅ | ✅ |
| 电子邮件模板 | ✅ 视觉+HTML | ✅ |
| 打开/单击跟踪 | ✅ | ✅ |
| 按座位定价 | ❌ 从不 | 💸 是的 |
| 供应商锁定 | ❌ 从不 | 💸 是的 |
| 价格 | 自由 / 企业 | 1000美元至10000美元/月 |
______________________________________________________________________
特性
- 📧 广播 --向任何细分市场发送一次性电子邮件,并提供日程安排支持
- ⚡ 活动 --具有多步流的事件触发自动化序列
- 👥 联系人和细分市场 --灵活的联系人属性+基于规则的动态细分
- 📐 电子邮件模板 --HTML编辑器+可视化构建器,完全可重用
- 📊 分析 --打开率、点击率、取消订阅、广播性能
- 🔑 API密钥 -用于编程访问的工作区范围的API密钥
- 📦 软件开发工具包 --用于Node.js、浏览器、React和Next.js的TypeScript SDK
- 🤖 MCP服务器 --原生HTTP MCP服务器:让任何AI代理创建和运行活动
- 🔔 事件跟踪 -REST API+SDK与PostHog和Customer.io兼容
- 🏢 多工作空间 --具有基于角色的访问权限的团队工作区(所有者/管理员/成员)
- 📬 退订 --自动取消订阅处理,符合CAN-SPAM标准
- 🎯 单击跟踪 --使用重定向代理进行全点击跟踪
______________________________________________________________________
建筑
OpenMail是一个由5个服务+1个SDK包组成的单一仓库,每个服务和SDK包都可以独立部署:
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ web/ │ │ api/ │ │ mcp/ │
│ React Vite │───▶│ Hono REST │◀───│ MCP HTTP │
│ Dashboard │ │ API + Auth │ │ AI Agent API │
└─────────────┘ └──────┬──────┘ └─────────────────┘
│
┌───────────┼───────────┐
│ │ │
┌──────▼─────┐ ┌──▼──────┐ ┌▼──────────┐
│ worker/ │ │ Postgres│ │ tracker/ │
│ BullMQ │ │ + Redis │ │ Pixel/ │
│ Workers │ └──────────┘ │ Clicks │
└────────────┘ └───────────┘
sdk/ ←── npm package (@openmail/sdk)| 服务 | 技术 | 目的 |
|---|---|---|
web/ | React+Vite+TanStack | 仪表板用户界面 |
api/ | Hono+Better Auth+Drizle | REST API+Auth |
mcp/ | Hono+MCP SDK | AI代理接口 |
worker/ | BullMQ+重新发送 | 电子邮件发送+事件 |
tracker/ | HONO | 打开/单击像素跟踪 |
sdk/ | TypeScript | 用于事件跟踪的npm包 |
______________________________________________________________________
快速开始
选项1:Docker Compose(推荐)
git clone https://github.com/ShadowWalker2014/openmail.git
cd openmail
cp .env.example .env
# Edit .env — add your Resend API key and a secret
docker compose up -d打开 http://localhost:5173 --注册,创建一个工作区,然后开始发送。
选项2:部署到铁路

每个服务都作为来自同一仓库的单独Railway服务进行部署。设置 根目录 到 / 和那个 Dockerfile路径 到服务的Dockerfile(例如。, api/Dockerfile).
请参阅 铁路部署指南 获取完整说明。
选项3:手动设置
先决条件: 包子、PostgreSQL、Redis
# Clone and install
git clone https://github.com/ShadowWalker2014/openmail.git
cd openmail
bun install
# Configure each service
cp api/.env.example api/.env.local
cp worker/.env.example worker/.env.local
cp tracker/.env.example tracker/.env.local
# Edit each file with your credentials
# Run database migrations
bun db:generate
bun db:migrate
# Start all services
bun dev:api # API on :3001
bun dev:mcp # MCP on :3002
bun dev:tracker # Tracker on :3003
bun dev:worker # Background workers
bun dev:web # Dashboard on :5173______________________________________________________________________
SDK——事件跟踪
从任何语言或框架跟踪用户事件。官方 @openmail/sdk 软件包与兼容 细分分析2.0 和 PostHog 接口,使迁移成为一行更改。
安装
# npm
npm install @openmail/sdk
# bun
bun add @openmail/sdk
# pnpm
pnpm add @openmail/sdk
# yarn
yarn add @openmail/sdkNode.js/服务器端
import { OpenMail } from "@openmail/sdk";
const openmail = new OpenMail({
apiKey: process.env.OPENMAIL_API_KEY!, // om_your_key from Settings → API Keys
});
// Identify a user — creates or updates a contact
await openmail.identify("alice@example.com", {
firstName: "Alice",
lastName: "Smith",
plan: "pro",
company: "Acme Corp",
});
// Track an event — triggers matching campaign automations
await openmail.track("plan_upgraded", {
from_plan: "starter",
to_plan: "pro",
mrr: 99,
}, { userId: "alice@example.com" });
// Access the full REST API
const broadcasts = await openmail.broadcasts.list();
const segment = await openmail.segments.create({
name: "Pro Users",
conditions: [{ field: "attributes.plan", operator: "eq", value: "pro" }],
});
// Flush buffered events before process exit
await openmail.flush();浏览器
import { OpenMailBrowser } from "@openmail/sdk/browser";
const openmail = new OpenMailBrowser({
apiKey: "om_your_public_key",
autoPageView: true, // auto-tracks page views and SPA navigations
persistence: "localStorage",
});
// On user login
await openmail.identify("alice@example.com", { plan: "pro" });
// Track events (fire-and-forget, automatically batched)
openmail.track("upgrade_clicked", { plan: "pro", page: "/pricing" });
// On logout
openmail.reset();反应
import { OpenMailProvider, useTrack, useAutoIdentify } from "@openmail/sdk/react";
import { useUser } from "./hooks";
// 1. Wrap your app root
function App() {
return (
);
}
// 2. Auto-identify on auth state changes
function AuthSync() {
const { user } = useUser();
useAutoIdentify(user?.email ?? null, {
firstName: user?.firstName,
plan: user?.plan,
});
return null;
}
// 3. Track events from any component
function UpgradeButton() {
const track = useTrack();
return (
track("upgrade_clicked", { plan: "pro" })}>
Upgrade to Pro
);
}Next.js
// app/layout.tsx — client wrapper for browser tracking
"use client";
import { OpenMailProvider } from "@openmail/sdk/nextjs";
export function TrackingProvider({ children }: { children: React.ReactNode }) {
return (
{children}
);
}// Server-side: route handlers, server actions, middleware
import { serverTrack, serverIdentify } from "@openmail/sdk/nextjs";
// In a route handler (uses OPENMAIL_API_KEY env var automatically)
export async function POST(req: Request) {
const { email, plan } = await req.json();
await serverIdentify(email, { plan });
await serverTrack("plan_upgraded", { plan }, { userId: email });
return Response.json({ ok: true });
}# .env.local
OPENMAIL_API_KEY=om_your_secret_key # server-side only
NEXT_PUBLIC_OPENMAIL_KEY=om_your_public_key # browser (public)从PostHog迁移
// Before (PostHog)
const posthog = new PostHog("phc_your_key", {
host: "https://app.posthog.com",
});
// After (OpenMail) — just change the host URL, no other code changes
const posthog = new PostHog("om_your_key", {
host: "https://api.openmail.win/api/ingest",
});从Customer.io迁移
// Before (Customer.io)
const cio = new TrackClient("site_id", "api_key");
// After (OpenMail) — just change the URL
const cio = new TrackClient("workspace_id", "om_your_key", {
url: "https://api.openmail.win/api/ingest/cio/v1",
});从分段迁移
这 @openmail/sdk API是 @segment/analytics-node:
// Before (Segment)
analytics.identify({ userId: "alice@example.com", traits: { plan: "pro" } });
analytics.track({ userId: "alice@example.com", event: "plan_upgraded", properties: { plan: "pro" } });
// After (OpenMail) — same method names, slightly different signature
openmail.identify("alice@example.com", { plan: "pro" });
openmail.track("plan_upgraded", { plan: "pro" }, { userId: "alice@example.com" });可用包
| 导入 | 环境 | 描述 |
|---|---|---|
@openmail/sdk | Node.js/Server | 完整的API+事件跟踪,与Segment/PostHog兼容 |
@openmail/sdk/browser | 浏览器 | 自动页面跟踪、匿名ID、批处理 |
@openmail/sdk/react | React 17+ | 提供者+ useTrack, useIdentify, useAutoIdentify 钩子 |
@openmail/sdk/nextjs | Next.js 13+ | serverTrack, serverIdentify,应用程序/页面路由器支持 |
______________________________________________________________________
用于AI代理的MCP服务器
OpenMail公开了一个本机 模型上下文协议(MCP)HTTP服务器 在 POST /mcp任何AI代理(Claude、GPT、Cursor等)都可以自主创建和管理整个电子邮件活动。
连接您的AI代理
{
"mcpServers": {
"openmail": {
"url": "https://mcp.openmail.win/mcp",
"headers": {
"Authorization": "Bearer om_your_workspace_api_key"
}
}
}
}可用MCP工具(共29个)
| 类别 | 工具 |
|---|---|
| 联系人 | list_contacts, create_contact, update_contact, delete_contact, track_event |
| 广播 | list_broadcasts, get_broadcast, create_broadcast, update_broadcast, schedule_broadcast, send_broadcast, delete_broadcast |
| 活动 | list_campaigns, create_campaign, update_campaign, pause_campaign |
| 片段 | list_segments, create_segment |
| 模板 | list_templates, create_template, update_template, delete_template |
| 分析 | get_analytics, get_broadcast_analytics |
| 资产 | list_assets, get_asset, upload_asset_from_url, upload_asset_base64, delete_asset |
示例:让克劳德发起一场活动
You: "Create a 'welcome' campaign for new signups that sends a welcome email immediately,
then a tips email 3 days later, targeting the 'new-users' segment"
Claude: [uses OpenMail MCP tools to create campaign, templates, and activate automatically]______________________________________________________________________
API 参考
所有API端点都可在 /api/v1/ (API密钥认证)或 /api/session/ws/:workspaceId/ (会话认证)。
认证
# Get your API key from the dashboard → Settings → API Keys
curl -H "Authorization: Bearer om_your_api_key" \
https://your-api.railway.app/api/v1/contacts核心终点
# Contacts
GET /api/v1/contacts # List with pagination + search
POST /api/v1/contacts # Create or upsert by email
GET /api/v1/contacts/:id # Get contact
PATCH /api/v1/contacts/:id # Update attributes
DELETE /api/v1/contacts/:id # Hard delete
GET /api/v1/contacts/:id/events # Contact event history
GET /api/v1/contacts/:id/sends # Contact email send history
# Events
POST /api/v1/events/track # { email, name, properties, occurredAt? }
GET /api/v1/events # List workspace events (paginated)
# Event Ingestion (PostHog/Customer.io compatible)
POST /api/ingest/capture # PostHog single event format
POST /api/ingest/batch # PostHog batch format (up to 100/call)
POST /api/ingest/identify # PostHog/Segment identify
POST /api/ingest/cio/v1/customers/:id # Customer.io identify
POST /api/ingest/cio/v1/customers/:id/events # Customer.io track
# Broadcasts
GET /api/v1/broadcasts # List all
POST /api/v1/broadcasts # Create draft
PATCH /api/v1/broadcasts/:id # Update draft (incl. schedule)
POST /api/v1/broadcasts/:id/send # Send immediately
POST /api/v1/broadcasts/:id/test-send # Send test email
# Campaigns
GET /api/v1/campaigns # List all
POST /api/v1/campaigns # Create
PATCH /api/v1/campaigns/:id # Update/activate/pause
POST /api/v1/campaigns/:id/steps # Add campaign step
# Segments
GET /api/v1/segments # List
POST /api/v1/segments # Create with conditions
GET /api/v1/segments/:id/people # List segment members
# Analytics
GET /api/v1/analytics/overview # 30-day workspace stats
GET /api/v1/analytics/broadcasts/:id # Broadcast performance事件跟踪示例
curl -X POST https://your-api.railway.app/api/v1/events/track \
-H "Authorization: Bearer om_..." \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"name": "user_upgraded",
"properties": { "plan": "pro", "mrr": 99 }
}'这会自动触发任何活动 triggerType: "event" 和 eventName: "user_upgraded".
📖 API完整文档→
______________________________________________________________________
配置
所需的环境变量
api/
| 变量 | 必填 | 描述 |
|---|---|---|
DATABASE_URL | ✅ | PostgreSQL连接字符串 |
REDIS_URL | ✅ | Redis连接字符串 |
BETTER_AUTH_SECRET | ✅ | 32+字符随机密码(openssl rand -base64 32) |
BETTER_AUTH_URL | ✅ | API服务的公共URL |
WEB_URL | ✅ | web仪表板的公共URL |
RESEND_API_KEY | ✅ | 重新发送API密钥-请参阅 电子邮件设置 在......下面 |
PLATFORM_FROM_EMAIL | ✅ | 系统电子邮件的发件人地址(必须在重新发送中验证) |
PLATFORM_FROM_NAME | -- | 发件人显示名称(默认值: OpenMail) |
DEFAULT_FROM_EMAIL | -- | 没有自定义密钥的工作区活动的回退发件人 |
DEFAULT_FROM_NAME | -- | 回退发件人名称(默认值: OpenMail) |
TRACKER_URL | -- | 跟踪服务的公共URL(启用打开/点击跟踪) |
worker/
| 变量 | 必填 | 描述 |
|---|---|---|
DATABASE_URL | ✅ | 相同的PostgreSQL实例 |
REDIS_URL | ✅ | 相同的Redis实例 |
RESEND_API_KEY | ✅ | 相同的重新发送API密钥 |
TRACKER_URL | ✅ | 跟踪器服务的公共URL |
DEFAULT_FROM_EMAIL | -- | 工作区活动电子邮件的回退发件人 |
______________________________________________________________________
电子邮件设置
OpenMail发送两类电子邮件:
| 类别 | 示例 | 受控 |
|---|---|---|
| 平台电子邮件 | 密码重置,工作区邀请 | PLATFORM_FROM_EMAIL |
| 活动电子邮件 | 广播、自动化序列 | 每个工作区重新发送键(设置→ 电子邮件发送) |
1.创建重新发送帐户
- 注册地址: resend.com
- 首选 API密钥 → 创建API密钥 (完全访问)
- 集
RESEND_API_KEY在你的api/环境
2.添加并验证发送域
⚠️ 你 不能 发送自@gmail.com,@outlook.com,或您不拥有的任何域名。 您必须添加一个您控制的域。
- 在重新发送仪表板中→ 领域 → 添加域
- 输入您的域名(例如。
mail.yourdomain.com或yourdomain.com) - 将重新发送提供的DNS记录(SPF、DKIM、DMARC)添加到您的DNS注册商
- 点击 验证 --通常需要1-5分钟
3.配置您的环境
# api/.env.local
RESEND_API_KEY=re_your_key_here
PLATFORM_FROM_EMAIL=noreply@yourdomain.com
PLATFORM_FROM_NAME=YourApp
DEFAULT_FROM_EMAIL=noreply@yourdomain.com
DEFAULT_FROM_NAME=YourApp4.(可选)每个工作区发送
每个工作区都可以配置其 拥有 在中重新发送API密钥和发件人地址 设置→ 邮件发送。这对于不同团队从不同域发送的多租户部署非常有用。
如果工作区没有配置自己的密钥,它将回退到平台的 RESEND_API_KEY 和 DEFAULT_FROM_EMAIL.
______________________________________________________________________
路线图
- \[\]可视化拖放电子邮件生成器(无层集成)
- \[\]Webhook摄取(从Stripe、Segment等接收事件)
- \[\]通过CSV导入联系人
- \[\]重新发送webhook→ 退货/投诉处理
- \[\]活动步骤延迟执行(等待节点)
- \[\]广播A/B测试
- \[\]SendGrid/AWS SES/邮戳提供商支持
- \[\]用于企业的SAML/SSO
- \[\]审核日志
______________________________________________________________________
贡献
我们希望您能帮助我们改进OpenMail。看 贡献.md 作为指导方针。
好的第一个问题:寻找 good first issue 标签。
# Fork, clone, install
git clone https://github.com/YOUR_USERNAME/openmail.git
cd openmail && bun install
# Create a branch
git checkout -b feat/your-feature
# Make changes, then submit a PR______________________________________________________________________
企业
OpenMail是 免费自托管 在...之下 弹性许可证2.0.
对于需要以下功能的企业部署:
- 管理托管 有SLA保证
- 企业SSO (SAML、OKTA、Azure AD)
- 优先支持 以及专门的入职培训
- 自定义集成 以及专业服务
- 气隙/内部 部署
→ 联系我们 kai@1flow.ai
______________________________________________________________________
技术栈
| 层 | 技术 |
|---|---|
| 前端 | React 19+Vite+TanStack路由器+TanStack查询 |
| UI | 顺风CSS+shadcn/UI组件 |
| 后端 | 荣誉 (超高速TypeScript HTTP) |
| 认证 | 更好的认证 |
| 数据库 | PostgreSQL+ Drizzle ORM |
| 排队 | BullMQ +Redis |
| 电子邮件 | 重发 |
| SDK | TypeScript(ESM+CJS,树可摇动) |
| MCP | @模型上下文协议/sdk |
| 部署 | 铁路 |
______________________________________________________________________
许可证
OpenMail根据 弹性许可证2.0(ELv2).
- ✅ 免费使用、自托管和修改
- ✅ 内部业务使用免费
- ❌ 无法将OpenMail作为 托管/管理服务 第三方
- ❌ 无法删除或绕过许可证保护
用于商业/托管服务→ 企业许可证
______________________________________________________________________
制作❤️ 由 OpenMail贡献者
**** --它帮助更多的开发人员找到OpenMail!
