名称: unione
描述: >
通过 UniOne Email API 发送交易和营销邮件。
管理邮件模板、验证邮箱地址、检查投递统计、
管理退订列表、配置 Webhook 以及处理域名设置。
UniOne 每年投递数十亿封邮件,送达率达 99.88%。
元数据:
openclaw:
emoji: "📧"
requires:
env:
- UNIONE_API_KEY
primaryEnv: UNIONE_API_KEY
UniOne 是一个提供 Web API 的交易邮件服务,用于大规模发送交易和营销邮件(最高可达 3000 封/秒)。此技能允许您发送邮件、管理模板、验证地址、追踪投递状态等。
所有请求都需要 UNIONE_API_KEY 环境变量。请将其作为 X-API-KEY 请求头传递。
基础 URL: https://api.unione.io/en/transactional/api/v1/{method}.json?platform=openclaw
所有方法均使用 POST 请求和 JSON 请求体。
在发件人域名验证通过前,邮件将无法投递。 在尝试发送任何邮件之前,请确保域名已设置完成:
domain/get-dns-records.jsoncurl -X POST "https://api.unione.io/en/transactional/api/v1/domain/get-dns-records.json?platform=openclaw" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $UNIONE_API_KEY" \
-d '{"domain": "yourdomain.com"}'
API 响应 返回原始值(非可直接粘贴的 DNS 记录):
{
"status": "success",
"domain": "yourdomain.com",
"verification-record": "unione-validate-hash=483bb362ebdbeedd755cfb1d4d661",
"dkim": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDo7"
}
用户必须根据这些值创建 3 条 DNS TXT 记录:
| 记录主机 | 记录类型 | 值 |
|---|---|---|
@ |
TXT | unione-validate-hash=<响应中的 verification-record> |
us._domainkey |
TXT | k=rsa; p=<响应中的 dkim> |
@ |
TXT | v=spf1 include:spf.unione.io ~all |
请清晰地向用户展示这 3 条记录,并指导他们在其 DNS 提供商(如 Cloudflare、Route53、GoDaddy 等)处添加。SPF 记录始终相同——API 不会返回此记录。
domain/validate-verification.json用户添加 DNS 记录后:
curl -X POST "https://api.unione.io/en/transactional/api/v1/domain/validate-verification.json?platform=openclaw" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $UNIONE_API_KEY" \
-d '{"domain": "yourdomain.com"}'
domain/validate-dkim.jsoncurl -X POST "https://api.unione.io/en/transactional/api/v1/domain/validate-dkim.json?platform=openclaw" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $UNIONE_API_KEY" \
-d '{"domain": "yourdomain.com"}'
domain/list.jsoncurl -X POST "https://api.unione.io/en/transactional/api/v1/domain/list.json?platform=openclaw" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $UNIONE_API_KEY" \
-d '{}'
如果域名验证失败: DNS 传播可能需要长达 48 小时。建议用户等待后重试,或检查其 DNS 记录是否有拼写错误。
发起 API 请求时,应对可重试错误实施指数退避重试:
可重试错误(应使用指数退避进行重试):
| HTTP 状态码 | 含义 | 重试策略 |
|---|---|---|
| 429 | 速率限制 | 等待后重试。如果存在 Retry-After 头,请遵循其指示 |
| 500 | 内部服务器错误 | 最多重试 3 次 |
| 502 | 网关错误 | 最多重试 3 次 |
| 503 | 服务不可用 | 最多重试 3 次 |
| 504 | 网关超时 | 最多重试 3 次 |
推荐的重试时间表:
| 尝试次数 | 延迟 |
|---|---|
| 1 | 立即 |
| 2 | 1 秒 |
| 3 | 5 秒 |
| 4 | 30 秒 |
不可重试错误(不应重试):
| HTTP 状态码 | 含义 | 操作 |
|---|---|---|
| 400 | 请求错误 | 修复请求参数 |
| 401 | 未授权 | 检查 API 密钥 |
| 403 | 禁止访问 | 检查权限 / 域名验证状态 |
| 404 | 端点未找到 | 检查方法路径 |
| 413 | 负载过大 | 减小请求大小 |
对于 email/send.json,务必包含 idempotency_key,以防止重试时重复发送。这对生产系统至关重要。
idempotency_key 是请求体中传递的唯一字符串(建议使用 UUID)。如果 UniOne 收到两个具有相同密钥的请求,第二个请求将返回第一个请求的结果,而不会再次发送邮件。
为每个逻辑发送操作生成唯一的幂等性密钥,并在重试同一发送时复用相同的密钥。
email/send.json向一个或多个收件人发送交易或营销邮件。支持通过替换变量、模板、附件、追踪和元数据进行个性化设置。
curl -X POST "https://api.unione.io/en/transactional/api/v1/email/send.json?platform=openclaw" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $UNIONE_API_KEY" \
-d '{
"idempotency_key": "unique-uuid-here",
"message": {
"recipients": [
{
"email": "recipient@example.com",
"substitutions": {
"to_name": "John Smith"
}
}
],
"body": {
"html": "<h1>Hello, {{to_name}}!</h1><p>Your order has been confirmed.</p>",
"plaintext": "Hello, {{to_name}}! Your order has been confirmed."
},
"subject": "Order Confirmation",
"from_email": "noreply@yourdomain.com",
"from_name": "Your Store"
}
}'
const response = await fetch("https://api.unione.io/en/transactional/api/v1/email/send.json?platform=openclaw", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": process.env.UNIONE_API_KEY
},
body: JSON.stringify({
idempotency_key: crypto.randomUUID(),
message: {
recipients: [{ email: "recipient@example.com", substitutions: { to_name: "John" } }],
body: {
html: "<h1>Hello, {{to_name}}!</h1><p>Your order has been confirmed.</p>",
plaintext: "Hello, {{to_name}}! Your order has been confirmed."
},
subject: "Order Confirmation",
from_email: "noreply@yourdomain.com",
from_name: "Your Store"
}
})
});
const data = await response.json();
// data.status === "success" → data.job_id, data.emails
import requests, uuid, os
response = requests.post(
"https://api.unione.io/en/transactional/api/v1/email/send.json?platform=openclaw",
headers={
"Content-Type": "application/json",
"X-API-KEY": os.environ["UNIONE_API_KEY"]
},
json={
"idempotency_key": str(uuid.uuid4()),
"message": {
"recipients": [{"email": "recipient@example.com", "substitutions": {"to_name": "John"}}],
"body": {
"html": "<h1>Hello, {{to_name}}!</h1><p>Your order has been confirmed.</p>",
"plaintext": "Hello, {{to_name}}! Your order has been confirmed."
},
"subject": "Order Confirmation",
"from_email": "noreply@yourdomain.com",
"from_name": "Your Store"
}
}
)
data = response.json() # data["status"] == "success" → data["job_id"], data["emails"]
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"github.com/google/uuid"
)
func sendEmail() error {
payload := map[string]interface{}{
"idempotency_key": uuid.New().String(),
"message": map[string]interface{}{
"recipients": []map[string]interface{}{
{"email": "recipient@example.com", "substitutions": map[string]string{"to_name": "John"}},
},
"body": map[string]string{
"html": "<h1>Hello, {{to_name}}!</h1><p>Your order has been confirmed.</p>",
"plaintext": "Hello, {{to_name}}! Your order has been confirmed.",
},
"subject": "Order Confirmation",
"from_email": "noreply@yourdomain.com",
"from_name": "Your Store",
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST",
"https://api.unione.io/en/transactional/api/v1/email/send.json?platform=openclaw",
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-KEY", os.Getenv("UNIONE_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result) // result["status"] == "success"
return nil
}
$ch = curl_init("https://api.unione.io/en/transactional/api/v1/email/send.json?platform=openclaw");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: " . getenv("UNIONE_API_KEY")
],
CURLOPT_POSTFIELDS => json_encode([
"idempotency_key" => bin2hex(random_bytes(16)),
"message" => [
"recipients" => [["email" => "recipient@example.com", "substitutions" => ["to_name" => "John"]]],
"body" => [
"html" => "<h1>Hello, {{to_name}}!</h1><p>Your order has been confirmed.</p>",
"plaintext" => "Hello, {{to_name}}! Your order has been confirmed."
],
"subject" => "Order Confirmation",
"from_email" => "noreply@yourdomain.com",
"from_name" => "Your Store"
]
])
]);
$response = curl_exec($ch);
$data = json_decode($response, true); // $data["status"] === "success"
成功响应:
{
"status": "success",
"job_id": "1ZymBc-00041N-9X",
"emails": ["recipient@example.com"]
}
message 对象的完整参数:
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
recipients |
数组 | 是 | 收件人对象数组。每个对象包含 email(必需)、substitutions(对象)、metadata(对象) |
body.html |
字符串 | 是* | HTML 内容。使用 {{variable}} 进行变量替换 |
body.plaintext |
字符串 | 否 | 纯文本版本 |
subject |
字符串 | 是* | 邮件主题行。支持 {{substitutions}} |
from_email |
字符串 | 是* | 发件人邮箱(必须来自已验证的域名) |
from_name |
字符串 | 否 | 发件人显示名称 |
reply_to |
字符串 | 否 | 回复邮箱地址 |
template_id |
字符串 | 否 | 使用存储的模板代替 body/subject |
tags |
数组 | 否 | 用于分类和过滤的标签 |
track_links |
0/1 | 否 | 启用点击追踪(默认:0) |
track_read |
0/1 | 否 | 启用打开追踪(默认:0) |
global_language |
字符串 | 否 | 退订页脚语言:en, de, fr, es, it, pl, pt, ru, ua, be |
template_engine |
字符串 | 否 | "simple"(默认)、"velocity" 或 "liquid" |
global_substitutions |
对象 | 否 | 对所有收件人可用的变量 |
attachments |
数组 | 否 | {type, name, content} 数组,其中 content 为 base64 编码 |
skip_unsubscribe |
0/1 | 否 | 跳过退订页脚(仅对交易邮件使用 1) |
headers |
对象 | 否 | 自定义邮件头 |
*如果使用了 template_id,则非必需。
顶级参数:
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
idempotency_key |
字符串 | 推荐 | 唯一密钥(UUID),用于防止重试时重复发送。最多 36 个字符。 |
使用模板发送:
curl -X POST "https://api.unione.io/en/transactional/api/v1/email/send.json?platform=openclaw" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $UNIONE_API_KEY" \
-d '{
"idempotency_key": "unique-uuid-here",
"message": {
"recipients": [
{
"email": "customer@example.com",
"substitutions": {
"to_name": "Alice",
"order_id": "ORD-12345",
"total": "$59.99"
}
}
],
"template_id": "your-template-id",
"from_email": "shop@yourdomain.com",
"from_name": "My Shop"
}
}'
向多个收件人发送个性化邮件:
curl -X POST "https://api.unione.io/en/transactional/api/v1/email/send.json?platform=openclaw" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $UNIONE_API_KEY" \
-d '{
"idempotency_key": "unique-uuid-here",
"message": {
"recipients": [
{"email": "alice@example.com", "substitutions": {"to_name": "Alice"}},
{"email": "bob@example.com", "substitutions": {"to_name": "Bob"}}
],
"body": {
"html": "<p>Hi {{to_name}}, check out our new {{promo_name}}!</p>"
},
"subject": "Special offer for you, {{to_name}}!",
"from_email": "marketing@yourdomain.com",
"from_name": "Marketing Team",
"global_substitutions": {"promo_name": "Summer Sale"},
"track_links": 1,
"track_read": 1,
"tags": ["promo", "summer-2026"]
}
}'
email-validation/single.json验证邮箱地址是否存在且可投递。
curl -X POST "https://api.unione.io/en/transactional/api/v1/email-validation/single.json?platform=openclaw" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $UNIONE_API_KEY" \
-d '{"email": "user@example.com"}'
响应:
{
"status": "success",
"email": "user@example.com",
"result": "valid",
"local_part": "user",
"domain": "example.com",
"mx_found": true,
"mx_record": "mail.example.com"
}
可能的 result 值:"valid"、"invalid"、"unresolvable"、"unknown"。