Tên miền
Bạn chỉ gửi được email từ tên miền đã thêm vào Hạ Tầng và đã xác minh. Mỗi tên miền có khoá DKIM và tên miền phụ return path riêng, để hộp thư người nhận kiểm tra được thư thật sự do bạn gửi. Trang này hướng dẫn thêm tên miền, các bản ghi DNS, xác minh, cấu hình một chạm bằng Domain Connect và cách xử lý khi một bản ghi không xác minh được.
Trước khi bắt đầu
- Quyền sửa DNS của tên miền (Cloudflare, nhà đăng ký tên miền hoặc nhà cung cấp DNS).
- Nếu dùng API: key có phạm vi
email:write. Các endpoint tên miền từ chối key không có phạm vi này.
Chọn tên miền để gửi
Phần tên miền trong địa chỉ From phải trùng khớp với một tên miền đã xác minh. Muốn gửi từ [email protected] thì phải thêm updates.example.com; thêm example.com là chưa đủ, và ngược lại.
Tên miền phụ như updates.example.com hay mail.example.com giữ uy tín gửi thư tách biệt với tên miền gốc. Nếu một chiến dịch không suôn sẻ, thư nhân viên gửi từ example.com không bị ảnh hưởng. Nhiều đội dùng một tên miền phụ cho email giao dịch và một tên miền phụ khác cho chiến dịch email.
Thêm tên miền
- cURL
- Node.js
- Python
- PHP
curl -X POST https://api.hatang.dev/domains \
-H "Authorization: Bearer $HATANG_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "shop.vn" }'
import { Hatang } from "@hatang/sdk";
const hatang = new Hatang(process.env.HATANG_API_KEY, { baseUrl: "https://api.hatang.dev" });
const { data: domain, error } = await hatang.domains.create({ name: "shop.vn" });
if (error) throw new Error(error.message);
console.table(domain.records);
import os
import requests
res = requests.post(
"https://api.hatang.dev/domains",
headers={"Authorization": f"Bearer {os.environ['HATANG_API_KEY']}"},
json={"name": "shop.vn"},
)
res.raise_for_status()
for record in res.json()["records"]:
print(record["type"], record["name"], record["value"])
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.hatang.dev']);
$res = $client->post('/domains', [
'headers' => ['Authorization' => 'Bearer ' . getenv('HATANG_API_KEY')],
'json' => ['name' => 'shop.vn'],
]);
$domain = json_decode($res->getBody(), true);
Trong dashboard, mở Email → Tên miền, nhập tên miền vào ô Tên miền rồi bấm Thêm tên miền. Mục Tuỳ chọn nâng cao có các thiết lập giống các trường API dưới đây.
| Trường | Mặc định | Mô tả |
|---|---|---|
name | bắt buộc | Tên miền hoặc tên miền phụ, ví dụ shop.vn hay updates.shop.vn. Được lưu ở dạng chữ thường. |
custom_return_path | send | Nhãn tên miền phụ cho địa chỉ nhận thư trả lại và SPF: send thành send.shop.vn. Chữ, số và dấu gạch ngang, tối đa 63 ký tự. Trong dashboard: Return-Path tuỳ chỉnh. |
tracking_subdomain | không có | Nhãn tuỳ chọn cho link theo dõi mang tên miền của bạn, ví dụ links thành links.shop.vn. Phải khác nhãn return path. Trong dashboard: Tên miền phụ theo dõi. Xem Theo dõi mở và nhấp. |
open_tracking | false | Chèn pixel theo dõi lượt mở vào email HTML gửi từ tên miền này. |
click_tracking | false | Viết lại link trong email HTML gửi từ tên miền này để ghi nhận lượt nhấp. |
region | vùng của nền tảng | Nhận để tương thích Resend và được lưu lại. Việc gửi luôn dùng vùng Amazon SES của nền tảng. |
Response (201) là tên miền kèm các bản ghi cần thêm:
{
"object": "domain",
"id": "dom_0199e6c17a2b7f009c1e3f6a2b1d9e10",
"name": "shop.vn",
"status": "not_started",
"created_at": "2026-10-14T09:12:03.000Z",
"region": "us-west-2",
"dkim_selector": "rs7hq2kx9p",
"open_tracking": false,
"click_tracking": false,
"tracking_subdomain": null,
"tracking_domain_verified": false,
"custom_return_path": "send",
"ses_status": "pending",
"tls": "opportunistic",
"capabilities": { "sending": "enabled", "receiving": "disabled" },
"records": [
{ "record": "MX", "name": "send.shop.vn", "type": "MX", "ttl": "Auto", "status": "not_started", "value": "feedback-smtp.us-west-2.amazonses.com", "priority": 10, "required": true },
{ "record": "SPF", "name": "send.shop.vn", "type": "TXT", "ttl": "Auto", "status": "not_started", "value": "v=spf1 include:amazonses.com ~all", "required": true },
{ "record": "DKIM", "name": "rs7hq2kx9p._domainkey.shop.vn", "type": "TXT", "ttl": "Auto", "status": "not_started", "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqh…", "required": true },
{ "record": "DMARC", "name": "_dmarc.shop.vn", "type": "TXT", "ttl": "Auto", "status": "not_started", "value": "v=DMARC1; p=none;", "required": false }
]
}
Thêm một tên miền đã có sẽ nhận lỗi 409.
Các bản ghi DNS
Luôn chép tên và giá trị từ dashboard hoặc từ mảng records. Các giá trị dưới đây chỉ là ví dụ.
| Bản ghi | Loại | Tên | Giá trị | Bắt buộc |
|---|---|---|---|---|
| DKIM | TXT | <selector>._domainkey.shop.vn | v=DKIM1; k=rsa; p=<khoá công khai> | Có |
| MX của return path | MX, ưu tiên 10 | send.shop.vn | feedback-smtp.<vùng>.amazonses.com | Có |
| SPF của return path | TXT | send.shop.vn | v=spf1 include:amazonses.com ~all | Có |
| DMARC | TXT | _dmarc.shop.vn | v=DMARC1; p=none; | Không, nhưng nên có |
| Theo dõi | CNAME | links.shop.vn | Tên máy chủ theo dõi hiển thị trong dashboard | Chỉ khi có tên miền phụ theo dõi |
| Nhận thư | MX, ưu tiên 10 | shop.vn | Máy chủ nhận thư hiển thị trong dashboard | Chỉ khi bật nhận email |
DKIM
Hạ Tầng tạo một khoá RSA 2048 bit cho mỗi tên miền. Nửa công khai nằm trong bản ghi TXT dưới một selector bắt đầu bằng rs và tám ký tự ngẫu nhiên (trường dkim_selector). Mọi thư đều được ký bằng nửa bí mật cho tên miền của bạn, nhờ vậy DMARC đạt qua DKIM.
Khoá 2048 bit dài hơn 255 ký tự. Phần lớn nhà cung cấp DNS tự tách thành nhiều chuỗi; bạn chỉ cần dán nguyên giá trị vào một bản ghi. Hạ Tầng bỏ qua khoảng trắng khi so khoá.
Return path: MX và SPF trên send.
Địa chỉ nhận thư trả lại (envelope sender, hay Return-Path) của mọi thư nằm trên tên miền phụ return path, ví dụ bounce+…@send.shop.vn. Hai bản ghi trên tên miền phụ này giúp nó hoạt động:
- Bản ghi MX đưa thư trả lại và báo spam về Amazon SES, rồi SES báo lại cho Hạ Tầng.
- Bản ghi TXT SPF cho phép Amazon SES gửi thay tên miền phụ đó. Vì return path là tên miền phụ của tên miền bạn, SPF căn chỉnh (align) với tên miền trong
Fromtheo chế độ căn chỉnh relaxed của DMARC.
Các bản ghi nằm trên tên miền phụ chứ không phải tên miền gốc, nên không bao giờ đụng tới SPF hay MX mà tên miền gốc đang có. Nếu tên miền phụ đã có bản ghi SPF, Hạ Tầng chấp nhận mọi bản ghi v=spf1 có chứa include:amazonses.com.
DMARC
DMARC cho hộp thư người nhận biết phải làm gì với thư không đạt căn chỉnh SPF và DKIM. Hạ Tầng đề xuất v=DMARC1; p=none;, tức là chỉ theo dõi. Mọi bản ghi bắt đầu bằng v=DMARC1 đều được tính là đã có, nên nếu đã có chính sách riêng thì cứ giữ. DMARC không chặn việc xác minh. Gmail và Yahoo yêu cầu người gửi số lượng lớn phải có DMARC, nên hãy thêm. Xem Khả năng vào hộp thư.
Theo dõi và nhận thư
Hai bản ghi này chỉ xuất hiện khi bạn dùng tính năng tương ứng: CNAME theo dõi khi tên miền có tên miền phụ theo dõi, MX nhận thư khi bạn bật nhận email. Cả hai đều không chặn việc gửi. Xem Theo dõi mở và nhấp và Nhận email.
Nhiều nhà cung cấp DNS tự nối tên zone vào tên bạn nhập. Nhập send.shop.vn vào ô Name của zone shop.vn có thể tạo ra send.shop.vn.shop.vn. Với những nhà cung cấp như vậy, chỉ nhập phần đứng trước tên miền (send, rs7hq2kx9p._domainkey, _dmarc).
Xác minh tên miền
Khi đã thêm bản ghi, bắt đầu xác minh:
- Dashboard: mở tên miền và bấm Xác minh bản ghi DNS. Trong lúc tên miền đang chờ, trang tự kiểm tra lại và tự làm mới.
- API:
POST /domains/{id}/verify, hoặchatang.domains.verify(id)trong SDK Node.js.
curl -X POST https://api.hatang.dev/domains/dom_0199e6c17a2b7f009c1e3f6a2b1d9e10/verify \
-H "Authorization: Bearer $HATANG_API_KEY"
{ "object": "domain", "id": "dom_0199e6c17a2b7f009c1e3f6a2b1d9e10", "status": "pending" }
Hạ Tầng kiểm tra mọi bản ghi ngay lập tức, sau đó tiếp tục kiểm tra ở chế độ nền cho tới khi tên miền được xác minh. Thay đổi DNS có thể mất tới một giờ để lan truyền. Tên miền Đã xác minh khi mọi bản ghi bắt buộc (DKIM, MX và SPF của return path) đều khớp và Amazon SES đã xác nhận chữ ký DKIM. Bản ghi không bắt buộc không bao giờ làm chậm việc xác minh.
Trạng thái tên miền
| Trạng thái | Trong dashboard | Ý nghĩa |
|---|---|---|
not_started | Chưa bắt đầu | Tên miền đã được thêm nhưng chưa yêu cầu xác minh. |
pending | Đang chờ | Hạ Tầng đang kiểm tra. Còn bản ghi bắt buộc chưa khớp, hoặc Amazon SES chưa xác nhận DKIM. |
verified | Đã xác minh | Gửi được từ tên miền này. |
temporary_failure | Lỗi tạm thời | Tra cứu DNS lỗi vì lý do khác "không tìm thấy", ví dụ hết thời gian chờ. Hạ Tầng sẽ thử lại. |
failed | Thất bại | Xác minh thất bại, ví dụ Amazon SES từ chối cấu hình DKIM. Sửa bản ghi rồi xác minh lại. |
Mỗi bản ghi cũng có status riêng (not_started, pending, verified hoặc failed) và, khi lỗi, trường last_error cho biết Hạ Tầng thấy gì thay vào đó, như found: nothing hoặc giá trị đang có.
Hạ Tầng gửi webhook domain.created, domain.updated và domain.deleted, kèm tên miền giống như GET /domains/{id} trả về. Mỗi lần trạng thái đổi sẽ bắn domain.updated.
Cấu hình một chạm với Domain Connect
Nếu nhà cung cấp DNS hỗ trợ Domain Connect, trang tên miền có khung Bản ghi DNS với nút Tự động cấu hình với tên nhà cung cấp. Bấm vào, đăng nhập ở nhà cung cấp DNS và đồng ý thay đổi. Nhà cung cấp thêm bản ghi, đưa bạn quay lại Hạ Tầng và việc xác minh bắt đầu ngay. Nút Cài đặt thủ công đưa bạn tới bảng bản ghi để tự thêm.
Domain Connect thêm:
- bản ghi MX của return path và quy tắc SPF (
include:amazonses.com, gộp vào bản ghi SPF sẵn có trên tên miền phụ đó), - bản ghi DKIM,
- bản ghi DMARC (
v=DMARC1; p=none;), - CNAME theo dõi, khi tên miền có tên miền phụ theo dõi.
Xem kỹ những thay đổi nhà cung cấp DNS hiển thị trước khi đồng ý, nhất là khi tên miền đã có bản ghi DMARC bạn muốn giữ.
Khi nhà cung cấp DNS không hỗ trợ Domain Connect nhưng tên miền nằm trên Cloudflare, trang tên miền có link mở thẳng trang bản ghi DNS của zone.
Qua API:
# Tên miền này có cấu hình một chạm được không?
curl https://api.hatang.dev/domains/$DOMAIN_ID/domain-connect -H "Authorization: Bearer $HATANG_API_KEY"
# { "object": "domain_connect", "available": true, "reason": null, "dns_host": "Cloudflare", "zone": "shop.vn" }
# Lấy URL đã ký để chuyển người dùng tới
curl -X POST https://api.hatang.dev/domains/$DOMAIN_ID/domain-connect \
-H "Authorization: Bearer $HATANG_API_KEY" -H "Content-Type: application/json" -d '{}'
# { "object": "domain_connect", "id": "dom_…", "url": "https://…" }
Khi available là false, reason là no_domain_connect (nhà cung cấp DNS không hỗ trợ), template_not_supported (có hỗ trợ Domain Connect nhưng chưa hỗ trợ template của Hạ Tầng) hoặc not_configured. POST nhận redirect_uri tuỳ chọn; nếu không có, người dùng quay về trang tên miền trong dashboard.
GET /domains/{id}/dns-provider cho biết nhà cung cấp DNS đang phục vụ tên miền:
{ "object": "dns_provider", "zone": "shop.vn", "provider": "cloudflare", "nameservers": ["ada.ns.cloudflare.com", "bob.ns.cloudflare.com"], "cloudflare_url": "https://dash.cloudflare.com/…" }
Return path tuỳ chỉnh
Nhãn return path là send, trừ khi bạn chọn nhãn khác lúc thêm tên miền. Chỉ đổi khi send.shop.vn đã được dùng cho việc khác, ví dụ bản ghi thư trả lại của một dịch vụ email khác. Nhãn không đổi được về sau: hãy xoá tên miền rồi thêm lại với nhãn mới.
Sửa hoặc xoá tên miền
PATCH /domains/{id} đổi các thiết lập được phép đổi sau khi tạo:
curl -X PATCH https://api.hatang.dev/domains/$DOMAIN_ID \
-H "Authorization: Bearer $HATANG_API_KEY" -H "Content-Type: application/json" \
-d '{ "open_tracking": true, "click_tracking": true, "tracking_subdomain": "links" }'
| Trường | Tác dụng |
|---|---|
open_tracking, click_tracking | Bật hoặc tắt theo dõi cho các email gửi từ lúc đó. |
tracking_subdomain | Đặt, đổi hoặc gỡ (null) tên miền phụ theo dõi. Một bản ghi CNAME mới xuất hiện để bạn thêm. |
capabilities.receiving | "enabled" hoặc "disabled". Xem Nhận email. |
DELETE /domains/{id} xoá tên miền và định danh Amazon SES của nó. Email còn trong hàng đợi của tên miền đó sẽ bị trả lại với lý do "Sending domain no longer exists".
Xử lý sự cố
| Hiện tượng | Nguyên nhân và cách sửa |
|---|---|
Bản ghi báo found: nothing | Bản ghi chưa có hoặc đặt sai tên. Kiểm tra tên zone có bị nối hai lần không (xem lưu ý ở trên), rồi chờ vài phút cho DNS cập nhật. |
| DKIM lỗi dù đã có bản ghi | Giá trị bị cắt hoặc bị sửa. Dán lại toàn bộ giá trị v=DKIM1; k=rsa; p=…. Một số nhà cung cấp cần đặt giá trị dài trong dấu ngoặc kép hoặc tách thành nhiều chuỗi. |
SPF trên send. lỗi | Tên miền phụ có bản ghi SPF không chứa include:amazonses.com, hoặc có hai bản ghi SPF. Chỉ giữ một bản ghi v=spf1 có chứa include:amazonses.com. |
Mọi bản ghi đều khớp nhưng trạng thái vẫn pending | Amazon SES chưa xác nhận DKIM. Thường chỉ chậm hơn DNS vài phút; bấm Kiểm tra lại DNS sau đó. |
| MX của return path xung đột với bản ghi khác | send.shop.vn đã có CNAME. Tên đã có CNAME thì không có bản ghi nào khác được. Gỡ CNAME, hoặc thêm lại tên miền với Return-Path tuỳ chỉnh khác. |
Lỗi 403 "The shop.vn domain is not verified" khi gửi | Tên miền của From chưa được thêm, chưa xác minh, hoặc là một tên miền phụ khác. Xem Chọn tên miền để gửi. |
Lỗi 401 restricted_api_key khi gửi | API key bị giới hạn vào tên miền khác. Dùng key của tên miền này hoặc key không giới hạn. |