Email relay
Thử nghiệmmail.vappcdn.com
Email giao dịch và hộp thư, không phải đi thuê uy tín gửi của người khác.
Tương thích với SMTP · IMAP · JMAP
- Chuẩn mở từ đầu đến cuối — SMTP, IMAP, JMAP. Không client độc quyền.
- SPF, DKIM và DMARC cấu hình theo từng domain, ký tự động.
- API gửi giao dịch cho hoá đơn, cảnh báo và đặt lại mật khẩu.
- Webhook trạng thái gửi để ứng dụng biết thư nào thực sự đến nơi.
Hướng dẫn dùng
1 · Khoá API và định dạng gọi
Mọi lời gọi đều là POST kèm bearer token, gửi tới origin bên dưới. Hãy để origin là một biến cấu hình, đừng rải nó khắp mã.
bash# API origin: https://cdn.vapp.vn
curl -sX POST https://cdn.vapp.vn/app/rpc/account/me \
-H "authorization: Bearer $VAPPCDN_API_KEY" \
-H 'content-type: application/json' \
-d '{"json":{}}'
# The {"json": …} envelope is required going IN as well as OUT.
# success: {"json": …}
# error: {"json":{"code":"FORBIDDEN","status":403,"message":"…"}}2 · Đăng ký domain gửi
Dùng subdomain, đừng dùng apex: uy tín gửi tách khỏi tên miền chạy website và DNS của bạn. Chúng tôi cũng tự áp dụng đúng như vậy.
bashcurl -sX POST https://cdn.vapp.vn/app/rpc/mail/addDomain \
-H "authorization: Bearer $VAPPCDN_API_KEY" \
-H 'content-type: application/json' \
-d '{"json":{"domain":"send.example.com","brandDomain":"example.com"}}'
# → expectations: { dkimSelector, spfMechanism, dkimRecord }
# Publish the selector WE return, not one you choose.3 · Đăng ba bản ghi, rồi xác minh
SPF trỏ theo TÊN MÁY chứ không phải IP — nên khi hạ tầng gửi của chúng tôi đổi máy, bạn không phải sửa gì. Nếu đã có SPF, hãy THÊM cơ chế vào bản ghi cũ; hai bản ghi SPF là lỗi vĩnh viễn ở mọi bên nhận.
dnssend.example.com TXT "v=spf1 a:mail.vappcdn.com ~all"
<selector>._domainkey.send.example.com TXT "v=DKIM1; k=rsa; p=…"
_dmarc.example.com TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
# then, until status is "active":
POST /app/rpc/mail/checkDomain {"json":{"domain":"send.example.com"}}
# Per-record status: ok · missing · invalid · unknown
# "unknown" means DNS did not answer us. It is NOT a failure — poll again.
# We check through a public resolver, never our own nameservers.4 · Tạo credential gửi
Một credential là một uy tín: hạn mức, warmup và danh sách chặn đều tính theo nó. Mỗi định danh gửi một credential riêng, và đừng dùng lại giữa các sản phẩm.
bashcurl -sX POST https://cdn.vapp.vn/app/rpc/mail/createCredential \
-H "authorization: Bearer $VAPPCDN_API_KEY" \
-H 'content-type: application/json' \
-d '{"json":{"domain":"send.example.com","name":"prod","localPart":"noreply"}}'
# → {"login":"noreply@send.example.com","secret":"…"}
# The secret is returned ONCE. There is no way to read it back.5 · Gửi, và đọc kết quả từng người nhận
Kết quả trả về theo TỪNG người nhận, vì chúng thực sự khác nhau. Chỉ nhìn mã HTTP là ghi nhầm một địa chỉ bị hoãn thành đã gửi.
bashcurl -sX POST https://cdn.vapp.vn/app/rpc/mail/send \
-H "authorization: Bearer $VAPPCDN_API_KEY" \
-H 'content-type: application/json' \
-d '{"json":{"from":"noreply@send.example.com","fromName":"Example",
"to":["someone@example.org"],
"subject":"Confirm your email",
"text":"Confirm here: https://example.com/confirm?t=…"}}'
# → {"messageCount":1,
# "outcomes":[{"to":"someone@example.org","status":"accepted","code":250}]}
#
# accepted we took responsibility for it — NOT the same as delivered
# deferred temporary; retry later, nothing is lost
# refused permanent; do not retry
# suppressed never left the building (suppression list, or an unverified domain)
#
# Each recipient gets its own message: we never put several addresses on one
# To:, which would disclose your recipient list to everyone on it.6 · Nhận thư — chuyển tiếp
Nhận thư cần MX trỏ về chúng tôi, gửi thì không. Đừng trỏ MX khi nhà cung cấp cũ vẫn đang nhận thư của bạn.
bash# catch-all: everything at the domain lands in one mailbox
POST /app/rpc/mail/addForward
{"json":{"domain":"example.com","kind":"catchall","destEmail":"you@example.net"}}
# one address
POST /app/rpc/mail/addForward
{"json":{"domain":"example.com","kind":"external",
"source":"support","destEmail":"team@example.com"}}
# Forwarded mail is re-sent by us, so the envelope sender is rewritten. You do
# not configure that; it is what keeps SPF passing at the final destination.Endpoint và mã lỗi
Mọi endpoint là POST /app/rpc/<namespace>/<procedure>, không có tham số trên đường dẫn hay query string. Gửi tới người nhận bất kỳ mở ra khi domain gửi của bạn chuyển sang active — trước đó API vẫn chạy đúng và trả về suppressed.
| name | accepts | notes |
|---|---|---|
| mail/addDomain | domains | Đăng ký domain gửi, trả về bản ghi cần đăng. |
| mail/checkDomain | domains | Kiểm tra SPF, DKIM, DMARC qua resolver công cộng. |
| mail/refreshDkim | domains | Lấy lại bản ghi DKIM nếu lần đầu chưa có. |
| mail/createCredential | senders | Tạo credential gửi. Secret chỉ hiện một lần. |
| mail/send | send | Gửi thư. Kết quả trả về theo từng người nhận. |
| mail/addForward | receive | Chuyển tiếp catch-all hoặc một địa chỉ. |
| mail/listForwards | receive | Liệt kê quy tắc chuyển tiếp của một domain. |
| mail/removeForward | receive | Xoá một quy tắc chuyển tiếp. |
| 401 UNAUTHORIZED | error | Thiếu khoá, hoặc khoá đã thu hồi. Đừng thử lại. |
| 403 FORBIDDEN | error | Chính sách từ chối — domain chưa xác minh, hoặc quá hạn mức gói. Không thử lại được. |
| 404 NOT_FOUND | error | Không tồn tại, HOẶC không thuộc về bạn — cố ý không phân biệt hai trường hợp. |
| 429 TOO_MANY_REQUESTS | error | Bị hoãn hoặc chạm giới hạn tốc độ. NÊN thử lại có backoff. |
| 503 SERVICE_UNAVAILABLE | error | Sự cố phía chúng tôi. Không có gì được gửi đi. Thử lại. |