# Bắt đầu nhanh: gửi email đầu tiên

Hướng dẫn này đưa bạn từ tài khoản mới đến một email đã gửi tới hộp thư người nhận trong khoảng mười phút. Bạn tạo API key, xác minh tên miền gửi, gửi thư qua REST API rồi xem lại nó trong dashboard.

## Trước khi bắt đầu

- Một tài khoản Hạ Tầng tại [app.hatang.dev](https://app.hatang.dev) đã bật module **Email** ([Doanh nghiệp và module](https://hatang.dev/vi/help/getting-started/modules)).
- Quyền sửa DNS của một tên miền bạn sở hữu, ví dụ `shop.vn`.
- Để tạo key, bạn cần là chủ sở hữu, quản trị viên, hoặc thành viên có quyền **Developer** ([Nhân viên và phân quyền](https://hatang.dev/vi/help/account/employees-and-roles)).

## 1. Tạo API key

1. Trong dashboard, mở **Cài đặt → API Keys** (trang này cũng có ở **Email → API Keys**).
2. Bấm **Tạo key**, đặt tên như `production`, và tích **Gửi** ở mục Email. Quyền này là scope `email:send`, đủ để gửi thư.
3. Có thể chọn **Tên miền gửi** để khoá key vào một tên miền.
4. Sao chép key. Key bắt đầu bằng `ht_` và chỉ hiện một lần.

Lưu key vào biến môi trường trên server:

```bash
export HATANG_API_KEY="ht_123..."
```

> **Caution**
>
> API key chỉ dùng ở server. Đừng bao giờ đặt key vào JavaScript chạy trên trình duyệt hay trong gói ứng dụng di động. Xem [Xác thực API](https://hatang.dev/vi/docs/guides/getting-started/authentication.md) về scope và key bị giới hạn.

## 2. Xác minh tên miền gửi

Hạ Tầng chỉ gửi từ những tên miền bạn đã chứng minh là của mình.

1. Mở **Email → Tên miền** và thêm tên miền, ví dụ `shop.vn`.
2. Thêm các bản ghi DNS mà Hạ Tầng hiển thị vào nhà cung cấp DNS của bạn.
3. Chờ tên miền chuyển sang **Đã xác minh**.

[Hướng dẫn Tên miền](https://hatang.dev/vi/docs/guides/email/domains.md) giải thích từng bản ghi, thời gian xác minh và cách xử lý tên miền mãi ở trạng thái chờ.

Nếu gửi từ tên miền chưa xác minh, API trả `403` với `name: "validation_error"` và thông báo như `The shop.vn domain is not verified. Please, add and verify your domain first.`

## 3. Gửi email

Gửi request `POST` tới `https://api.hatang.dev/emails`. Địa chỉ `from` phải thuộc tên miền đã xác minh. `to` nhận một địa chỉ hoặc một danh sách.

**cURL**

```bash
curl -X POST https://api.hatang.dev/emails \
  -H "Authorization: Bearer $HATANG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Shop <hello@shop.vn>",
    "to": ["customer@example.com"],
    "subject": "Đơn hàng của bạn đã được xác nhận",
    "html": "<p>Cảm ơn bạn đã đặt hàng!</p>"
  }'
```

**Node.js**

```bash
npm install @hatang/sdk
```

```js
import { Hatang } from "@hatang/sdk";

const hatang = new Hatang(process.env.HATANG_API_KEY, { baseUrl: "https://api.hatang.dev" });

const { data, error } = await hatang.emails.send({
  from: "Shop <hello@shop.vn>",
  to: ["customer@example.com"],
  subject: "Đơn hàng của bạn đã được xác nhận",
  html: "<p>Cảm ơn bạn đã đặt hàng!</p>",
});

if (error) {
  console.error(error.name, error.message);
} else {
  console.log("Đã gửi", data.id);
}
```

**Python**

```python
from hatang import Hatang, HatangError  # pip install hatang

hatang = Hatang()  # đọc HATANG_API_KEY
try:
    email = hatang.emails.send({
        "from": "Shop <hello@shop.vn>",
        "to": ["customer@example.com"],
        "subject": "Đơn hàng của bạn đã được xác nhận",
        "html": "<p>Cảm ơn bạn đã đặt hàng!</p>",
    })
    print("Đã gửi", email["id"])
except HatangError as err:
    print(err.name, err.message)
```

**PHP**

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client(['base_uri' => 'https://api.hatang.dev']);

$res = $client->post('/emails', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('HATANG_API_KEY')],
    'json' => [
        'from' => 'Shop <hello@shop.vn>',
        'to' => ['customer@example.com'],
        'subject' => 'Đơn hàng của bạn đã được xác nhận',
        'html' => '<p>Cảm ơn bạn đã đặt hàng!</p>',
    ],
    'http_errors' => false,
]);

$body = json_decode((string) $res->getBody(), true);
if ($res->getStatusCode() === 200) {
    echo 'Đã gửi ' . $body['id'];
} else {
    echo $body['name'] . ': ' . $body['message'];
}
```

Gọi thành công trả `200` kèm id của email mới:

```json
{ "id": "01a0b904-2978-73e8-b352-4a26fdca0ab5" }
```

Email được xếp hàng và gửi đi ở nền. Request cần `html`, `text` hoặc một `template` đã xuất bản; `to`, `cc` và `bcc` cộng lại tối đa 50 địa chỉ.

> **Tip: Thử lại an toàn**
>
> Thêm header `Idempotency-Key` (ví dụ mã đơn hàng) để request gửi lại không bao giờ gửi trùng email. Xem [Idempotency](https://hatang.dev/vi/docs/guides/getting-started/idempotency.md).

> **Note: Base URL của SDK Node.js**
>
> Truyền `baseUrl: "https://api.hatang.dev"` (hoặc đặt biến môi trường `HATANG_BASE_URL`) khi tạo client, như ví dụ trên.

## 4. Xem lại trong dashboard

- **Email → Email** liệt kê mọi thư cùng trạng thái: đang chờ, đã gửi, đã nhận, bị trả về, v.v. Mở một thư để xem từng người nhận và các sự kiện gửi.
- **Email → Logs** liệt kê mọi request API mà key của bạn đã gọi, kèm mã trạng thái, thời gian xử lý, body của request và response. Request lỗi hiện ở đây cùng lỗi của nó.

Bạn cũng đọc được trạng thái qua API:

```bash
curl https://api.hatang.dev/emails/01a0b904-2978-73e8-b352-4a26fdca0ab5 \
  -H "Authorization: Bearer $HATANG_API_KEY"
```

Response dưới đây đã được rút gọn:

```json
{
  "object": "email",
  "id": "01a0b904-2978-73e8-b352-4a26fdca0ab5",
  "from": "Shop <hello@shop.vn>",
  "to": ["customer@example.com"],
  "subject": "Đơn hàng của bạn đã được xác nhận",
  "last_event": "delivered",
  "created_at": "2026-10-23T09:34:12.952Z"
}
```

## Lỗi thường gặp

| Status | `name` | Nguyên nhân | Cách xử lý |
|---|---|---|---|
| 401 | `missing_api_key` | Thiếu header `Authorization` | Gửi `Authorization: Bearer ht_...` |
| 403 | `invalid_api_key` | Key sai hoặc đã bị thu hồi | Sao chép lại key hoặc tạo key mới |
| 401 | `restricted_api_key` | Key bị khoá vào tên miền gửi khác | Dùng key của tên miền này, hoặc key cho mọi tên miền |
| 403 | `validation_error` | Tên miền của `from` chưa xác minh | Hoàn tất [xác minh tên miền](https://hatang.dev/vi/docs/guides/email/domains.md) |
| 422 | `validation_error` | Thiếu trường hoặc trường không hợp lệ; `message` nêu tên trường | Sửa body của request |
| 403 | `product_disabled` | Module Email đang tắt | Nhờ chủ sở hữu hoặc quản trị viên bật lại |
| 429 | `rate_limit_exceeded` | Quá 10 request email mỗi giây | Chờ rồi thử lại ([Giới hạn tần suất](https://hatang.dev/vi/docs/guides/getting-started/rate-limits.md)) |
| 429 | `daily_quota_exceeded` | Doanh nghiệp đã dùng hết hạn mức email trong ngày | Chờ đến 0 giờ UTC hoặc nâng hạn mức ở **Email → Cài đặt email** |

## Bước tiếp theo

- [Nhận sự kiện gửi thư qua webhook](https://hatang.dev/vi/docs/guides/getting-started/webhooks.md)
- [Tổng quan Email](https://hatang.dev/vi/docs/guides/email/overview.md): template, chiến dịch email, danh sách nhận và thư đến
- [Số liệu và logs](https://hatang.dev/vi/docs/guides/email/metrics-and-logs.md)
- [Xác thực API](https://hatang.dev/vi/docs/guides/getting-started/authentication.md)

Source: https://hatang.dev/vi/docs/guides/getting-started/quickstart-email
