做这个项目是因为一件挺有意思的事。很多独立开发者需要验证用户邮箱,海外的免费服务一般一天只让发 100-200 封,想多用花Money。我就想,有没有那种拿来就能用的接口?于是就有了这个服务。
不过免费帮大家发邮件这事不太现实——发多了 IP 很快就被各大邮箱的反垃圾系统拉黑。所以换了个思路:收邮件。你不需要让用户填邮箱地址,只需要让用户用任意邮箱往指定地址发一封包含验证码的邮件就行,验证通过后你自然就拿到了用户的邮箱,再存到用户信息里就好了。
希望对你有用 📬
Base URL:
https://api.mailflow.lat所有接口返回 JSON 格式数据。
本服务提供邮箱所有权验证能力。核心流程:
/create 创建验证任务,获得收件地址和验证 token/result 查询验证状态,直到返回 verified/task
删除任务用户发送邮件 → verify+<alias>@mailflow.lat
↓
服务自动完成验证
↓
状态变为 verified → 可通过 /result 查询
| 层级 | 限制 | 说明 |
|---|---|---|
| 日级上限 | 1000 req/日/IP | 北京时间 00:00 重置,超限返回 429 |
| 秒级突发 | 10 req/s/IP | 允许短时突发 |
超限响应:
HTTP 429 Too Many Requests
Retry-After: <秒数>
{"error": "rate limit exceeded"}
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| GET | /health | 无 | 健康检查 |
| POST | /create | 无 | 创建验证任务 |
| POST | /result | 凭证 | 查询验证结果 |
| DELETE | /task | 凭证 | 删除任务 |
健康检查。
无参数,无请求体。
| 状态码 | 含义 | 响应体 |
|---|---|---|
| 200 | 服务正常 | {"status": "ok"} |
| 503 | 服务不可用 | {"status": "degraded"} |
curl https://api.mailflow.lat/health
{"status": "ok"}
创建邮箱验证任务。返回收件地址和验证信息,调用方需引导用户发送包含 token 的邮件。
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
| callback | string | 否 | 验证成功后的回调通知 URL,必须 HTTPS。留空则不回调 |
| 状态码 | 含义 | 响应体 |
|---|---|---|
| 200 | 创建成功 | 见下方 |
| 400 | 请求体格式错误 | {"error": "bad payload"} |
| 500 | 内部错误 | {"error": "internal error"} |
| 字段 | 类型 | 说明 |
|---|---|---|
| task_id | string | 任务唯一 ID |
| secret | string | 任务密钥,用于后续查询和删除 |
| signature | string | 凭证签名,用于身份验证 |
| string | 收件地址,格式
verify+<alias>@mailflow.lat
|
|
| subject | string | 建议邮件主题,格式
VERIFY-<alias>
|
| token | string | 验证令牌,必须出现在邮件正文中 |
| expire_at | integer | 过期时间(Unix 时间戳),默认 24 小时 |
curl -X POST https://api.mailflow.lat/create \
-H "Content-Type: application/json" \
-d '{"callback": ""}'
{
"task_id": "019f4326-9e8a-79f2-9221-99d5bfe25d06",
"secret": "WkveK_yM2FN0rxOkFQwLdqC93bCBCjV1VHoVOtZOAS0",
"signature": "d4568c5b552c5c56868f786d42a125637bda035fcc2aa05179111e7457339deb",
"mail": "verify+bjox5y9h@mailflow.lat",
"subject": "VERIFY-bjox5y9h",
"token": "YENsg_CZjz_23sEmrAko4JofsCDidM6nzS_L1yMfLZ8",
"expire_at": 1783624432
}
mail
地址告知用户,作为收件人subject 作为邮件主题(或自定义,但建议包含 alias)
token 放入邮件正文中 — 这是验证的关键
task_id、secret、signature,用于后续调用 /result 和
/task
callback URL查询验证结果。需要创建任务时返回的凭证信息。
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
| task_id | string | 是 | 任务 ID |
| secret | string | 是 | 任务密钥 |
| signature | string | 是 | 凭证签名 |
| 状态码 | 含义 | 响应体 |
|---|---|---|
| 200 | 等待验证 | {"task_id": "...", "status": "pending"} |
| 200 | 验证通过 | {"task_id": "...", "status": "verified", "email": "sender@example.com"} |
| 400 | 请求体格式错误 | {"error": "bad payload"} |
| 403 | 凭证无效 | {"error": "forbidden"} |
| 404 | 任务不存在或已过期 | {"error": "not found"} |
| 500 | 内部错误 | {"error": "internal error"} |
pending 状态:
| 字段 | 类型 | 说明 |
|---|---|---|
| task_id | string | 任务 ID |
| status | string | "pending" —
等待用户发送验证邮件 |
verified 状态:
| 字段 | 类型 | 说明 |
|---|---|---|
| task_id | string | 任务 ID |
| status | string | "verified" — 邮箱验证通过
|
| string | 验证通过的发件人邮箱地址 |
curl -X POST https://api.mailflow.lat/result \
-H "Content-Type: application/json" \
-d '{
"task_id": "019f4326-9e8a-79f2-9221-99d5bfe25d06",
"secret": "WkveK_yM2FN0rxOkFQwLdqC93bCBCjV1VHoVOtZOAS0",
"signature": "d4568c5b552c5c56868f786d42a125637bda035fcc2aa05179111e7457339deb"
}'
等待验证时:
{"task_id": "019f4326-9e8a-79f2-9221-99d5bfe25d06", "status": "pending"}
验证通过后:
{"task_id": "019f4326-9e8a-79f2-9221-99d5bfe25d06", "status": "verified", "email": "user@example.com"}
删除验证任务。需要创建任务时返回的凭证信息。
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
| task_id | string | 是 | 任务 ID |
| secret | string | 是 | 任务密钥 |
| signature | string | 是 | 凭证签名 |
| 状态码 | 含义 | 响应体 |
|---|---|---|
| 200 | 删除成功 | {"task_id": "...", "ok": true} |
| 400 | 请求体格式错误 | {"error": "bad payload"} |
| 403 | 凭证无效 | {"error": "forbidden"} |
| 404 | 任务不存在或已过期 | {"error": "not found"} |
| 500 | 内部错误 | {"error": "internal error"} |
curl -X DELETE https://api.mailflow.lat/task \
-H "Content-Type: application/json" \
-d '{
"task_id": "019f4326-9e8a-79f2-9221-99d5bfe25d06",
"secret": "WkveK_yM2FN0rxOkFQwLdqC93bCBCjV1VHoVOtZOAS0",
"signature": "d4568c5b552c5c56868f786d42a125637bda035fcc2aa05179111e7457339deb"
}'
{"task_id": "019f4326-9e8a-79f2-9221-99d5bfe25d06", "ok": true}
如果在创建任务时提供了 callback URL,验证通过后服务会向该 URL 发送 POST 请求:
POST <callback_url>
Content-Type: application/json
{
"task_id": "019f4326-9e8a-79f2-9221-99d5bfe25d06",
"status": "verified",
"email": "user@example.com",
"verified_at": 1783624500
}
| 字段 | 类型 | 说明 |
|---|---|---|
| task_id | string | 任务 ID |
| status | string | "verified" |
| string | 验证通过的发件人邮箱 | |
| verified_at | integer | 验证时间(Unix 时间戳) |
| HTTP 状态码 | error 值 | 触发条件 |
|---|---|---|
| 400 | bad payload |
请求体 JSON 格式错误或缺少必需字段 |
| 403 | forbidden |
凭证验证失败(task_id/secret/signature 不匹配) |
| 404 | not found |
任务不存在或已过期 |
| 429 | rate limit exceeded |
触发限流(日级或秒级) |
| 500 | internal error |
服务内部错误 |
| 503 | degraded |
服务不可用(仅 /health) |
# 1. 创建验证任务
RESPONSE=$(curl -s -X POST https://api.mailflow.lat/create \
-H "Content-Type: application/json" \
-d '{"callback": ""}')
# 解析返回值
TASK_ID=$(echo $RESPONSE | jq -r '.task_id')
SECRET=$(echo $RESPONSE | jq -r '.secret')
SIGNATURE=$(echo $RESPONSE | jq -r '.signature')
MAIL=$(echo $RESPONSE | jq -r '.mail')
TOKEN=$(echo $RESPONSE | jq -r '.token')
echo "请发送邮件到: $MAIL"
echo "邮件正文需包含: $TOKEN"
# 2. 轮询验证结果(用户发送邮件后)
while true; do
RESULT=$(curl -s -X POST https://api.mailflow.lat/result \
-H "Content-Type: application/json" \
-d "{\"task_id\":\"$TASK_ID\",\"secret\":\"$SECRET\",\"signature\":\"$SIGNATURE\"}")
STATUS=$(echo $RESULT | jq -r '.status')
if [ "$STATUS" = "verified" ]; then
echo "验证通过! 发件人: $(echo $RESULT | jq -r '.email')"
break
elif [ "$STATUS" = "pending" ]; then
echo "等待验证..."
sleep 5
else
echo "异常: $RESULT"
break
fi
done
# 3. 删除任务
curl -s -X DELETE https://api.mailflow.lat/task \
-H "Content-Type: application/json" \
-d "{\"task_id\":\"$TASK_ID\",\"secret\":\"$SECRET\",\"signature\":\"$SIGNATURE\"}"
# 1. Create verification task
RESPONSE=$(curl -s -X POST https://api.mailflow.lat/create \
-H "Content-Type: application/json" \
-d '{"callback": ""}')
# Parse response
TASK_ID=$(echo $RESPONSE | jq -r '.task_id')
SECRET=$(echo $RESPONSE | jq -r '.secret')
SIGNATURE=$(echo $RESPONSE | jq -r '.signature')
MAIL=$(echo $RESPONSE | jq -r '.mail')
TOKEN=$(echo $RESPONSE | jq -r '.token')
echo "Send email to: $MAIL"
echo "Body must include: $TOKEN"
# 2. Poll for result (after user sends email)
while true; do
RESULT=$(curl -s -X POST https://api.mailflow.lat/result \
-H "Content-Type: application/json" \
-d "{\"task_id\":\"$TASK_ID\",\"secret\":\"$SECRET\",\"signature\":\"$SIGNATURE\"}")
STATUS=$(echo $RESULT | jq -r '.status')
if [ "$STATUS" = "verified" ]; then
echo "Verified! Sender: $(echo $RESULT | jq -r '.email')"
break
elif [ "$STATUS" = "pending" ]; then
echo "Waiting..."
sleep 5
else
echo "Error: $RESULT"
break
fi
done
# 3. Delete task
curl -s -X DELETE https://api.mailflow.lat/task \
-H "Content-Type: application/json" \
-d "{\"task_id\":\"$TASK_ID\",\"secret\":\"$SECRET\",\"signature\":\"$SIGNATURE\"}"
# 创建任务
curl -s -X POST https://api.mailflow.lat/create \
-H "Content-Type: application/json" \
-d '{"callback": ""}'
# 查询结果
curl -s -X POST https://api.mailflow.lat/result \
-H "Content-Type: application/json" \
-d '{"task_id":"<task_id>","secret":"<secret>","signature":"<signature>"}'
# 删除任务
curl -s -X DELETE https://api.mailflow.lat/task \
-H "Content-Type: application/json" \
-d '{"task_id":"<task_id>","secret":"<secret>","signature":"<signature>"}'
# Create task
curl -s -X POST https://api.mailflow.lat/create \
-H "Content-Type: application/json" \
-d '{"callback": ""}'
# Query result
curl -s -X POST https://api.mailflow.lat/result \
-H "Content-Type: application/json" \
-d '{"task_id":"<task_id>","secret":"<secret>","signature":"<signature>"}'
# Delete task
curl -s -X DELETE https://api.mailflow.lat/task \
-H "Content-Type: application/json" \
-d '{"task_id":"<task_id>","secret":"<secret>","signature":"<signature>"}'
import requests
BASE = "https://api.mailflow.lat"
# 创建验证任务
resp = requests.post(f"{BASE}/create", json={"callback": ""})
task = resp.json()
print(f"收件地址: {task['mail']}")
print(f"邮件正文需包含: {task['token']}")
# 查询验证结果
resp = requests.post(f"{BASE}/result", json={
"task_id": task["task_id"],
"secret": task["secret"],
"signature": task["signature"],
})
result = resp.json()
print(f"状态: {result['status']}")
# verified 时: result["email"] 为发件人地址
# 删除任务
requests.delete(f"{BASE}/task", json={
"task_id": task["task_id"],
"secret": task["secret"],
"signature": task["signature"],
})
import requests
BASE = "https://api.mailflow.lat"
# Create verification task
resp = requests.post(f"{BASE}/create", json={"callback": ""})
task = resp.json()
print(f"Recipient: {task['mail']}")
print(f"Body must include: {task['token']}")
# Query verification result
resp = requests.post(f"{BASE}/result", json={
"task_id": task["task_id"],
"secret": task["secret"],
"signature": task["signature"],
})
result = resp.json()
print(f"Status: {result['status']}")
# When verified: result["email"] is the sender's address
# Delete task
requests.delete(f"{BASE}/task", json={
"task_id": task["task_id"],
"secret": task["secret"],
"signature": task["signature"],
})
const BASE = "https://api.mailflow.lat";
// 创建验证任务
const createResp = await fetch(`${BASE}/create`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ callback: "" }),
});
const task = await createResp.json();
console.log(`收件地址: ${task.mail}`);
console.log(`邮件正文需包含: ${task.token}`);
// 查询验证结果
const resultResp = await fetch(`${BASE}/result`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
task_id: task.task_id,
secret: task.secret,
signature: task.signature,
}),
});
const result = await resultResp.json();
console.log(`状态: ${result.status}`);
// verified 时: result.email 为发件人地址
// 删除任务
await fetch(`${BASE}/task`, {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
task_id: task.task_id,
secret: task.secret,
signature: task.signature,
}),
});
const BASE = "https://api.mailflow.lat";
// Create verification task
const createResp = await fetch(`${BASE}/create`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ callback: "" }),
});
const task = await createResp.json();
console.log(`Recipient: ${task.mail}`);
console.log(`Body must include: ${task.token}`);
// Query verification result
const resultResp = await fetch(`${BASE}/result`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
task_id: task.task_id,
secret: task.secret,
signature: task.signature,
}),
});
const result = await resultResp.json();
console.log(`Status: ${result.status}`);
// When verified: result.email is the sender's address
// Delete task
await fetch(`${BASE}/task`, {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
task_id: task.task_id,
secret: task.secret,
signature: task.signature,
}),
});