Skip to main content

Ha Tang Email

Ha Tang Email sends transactional and marketing email from your own domain. It speaks the same API as Resend, so existing Resend code works after you change the base URL and the API key, and it delivers through Amazon SES. This page shows how the pieces fit together and walks you through your first email.

What you get​

FeatureWhat it doesGuide
Sending domainsDKIM, SPF and return path for each domain, one-click DNS setup at supported DNS hostsDomains
REST APIPOST /emails and POST /emails/batch, scheduling, idempotency, tags, attachmentsSend email
SMTP relaysmtp.hatang.dev:5870 with STARTTLS, for frameworks and apps that only speak SMTPSMTP relay
TemplatesReusable emails with variables, sent by id or aliasTemplates
TrackingOpen and click tracking, optionally on your own subdomainOpen and click tracking
ReceivingMail sent to your domain becomes an email.received webhookReceive email
AudiencesContacts, segments, topics and custom propertiesContacts, segments and topics
BroadcastsMarketing email to a segment, now or on a schedule, with a hosted preferences pageBroadcasts
AutomationsPer-contact sequences started by events from your appAutomations
SuppressionsHard bounces, complaints and unsubscribes stop further sendsSuppressions and bounces
Metrics and logsDelivery, open, click, bounce and complaint rates, plus a log of every API callMetrics and logs

How a message travels​

  1. Your app calls POST /emails or hands a message to the SMTP relay. Both go through the same checks.
  2. Ha Tang checks that the From domain is verified and belongs to your business, skips suppressed recipients and reserves one email from your daily quota. It answers with the email id right away.
  3. A worker signs the message with your domain's DKIM key, sets the bounce address on your return-path subdomain (send. by default) and hands it to Amazon SES.
  4. Amazon SES reports deliveries, bounces and complaints back to Ha Tang. Ha Tang updates the email's status, adds hard bounces and complaints to your suppression list and sends you webhooks.

Before you start​

Send your first email​

1. Add and verify a domain​

In the dashboard, open Email → Domains, add your domain (for example example.com or a subdomain such as updates.example.com), publish the DNS records it shows and click Verify DNS records. The domain must reach the Verified status before you can send from it. The details are in Domains.

2. Create an API key​

Create a key with the email:send scope. Keep it on your server. Never put it in a browser or a mobile app.

3. Send​

curl -X POST https://api.hatang.dev/emails \
-H "Authorization: Bearer $HATANG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <[email protected]>",
"to": ["[email protected]"],
"subject": "Your order is confirmed",
"html": "<p>Thanks for your order!</p>"
}'

The response holds the email's id:

{ "id": "0199e6c1-7a2b-7f00-9c1e-3f6a2b1d9e10" }
note

The Node.js SDK returns { data, error } and never throws. Always pass baseUrl: "https://api.hatang.dev" (or set HATANG_BASE_URL), because the SDK's built-in default points at a local development server.

4. Follow the email​

  • In the dashboard, Email → Emails lists every email with its status, recipients and events.
  • GET /emails/{id} returns the email and its status; GET /emails/{id}/events returns each event and each recipient's state.
  • For real-time updates, subscribe a webhook to email.delivered, email.bounced and the other events. See Webhooks.

Dashboard map​

Sidebar itemWhat you do there
EmailsEvery email sent through the API, the SMTP relay or broadcasts. The Receiving tab lists mail received on your domains.
BroadcastsWrite, schedule and send marketing email to a segment.
TemplatesEdit, test and publish templates.
AudiencesContacts, segments, topics, properties and the suppression list.
AutomationsEvent-driven sequences and their runs.
MetricsVolume and rates per day.
DomainsSending and receiving domains, DNS records, tracking.
LogsEvery API call made with your keys.
API KeysCreate and revoke API keys.
WebhooksEndpoints that receive email events.
Email settingsSMTP connection details, daily quota, the emergency pause and the unsubscribe page.

API key scopes​

Grant each key only the scopes the system using it needs:

EndpointsRequired scope
POST /emails, POST /emails/batch, the SMTP relayemail:send
PATCH /emails/{id}, POST /emails/{id}/cancelemail:send
GET /emails, GET /emails/{id}, GET /emails/{id}/eventsemail:read (or email:send / email:write, which include it)
Domains, templates, contacts, segments, topics, broadcasts, events, automationsemail:write
GET /emails/metricsemail:read (or email:send / email:write, which include it)
GET /emails/receiving/*email:read or email:write, granted directly. email:send alone cannot read received mail.
GET /logs, GET /usageAny write scope

A key can also be limited to one sending domain. That key gets 401 restricted_api_key when it sends from another domain.

Limits at a glance​

LimitValue
REST API rate10 requests per second per business, shared by the email endpoints
Recipients per email50 across to, cc and bcc
Emails per batch call100
Email size40 MB, body and attachments together
SchedulingUp to 30 days ahead
Daily quotaSet per business, resets at midnight UTC. See Email settings or GET /usage.

The full list is in Limits and every error name is in Errors.

Next steps​

View this page as Markdown