Envoi · Getting started

Send your first transactional email

Ten minutes. DKIM-signed. From your own domain.

1 · Create a team

Open envoi.productcraft.co. If you don't have a ProductCraft account yet, sign up via Heimdall first — Envoi uses the same account. Once signed in, create a team. The team is the boundary for your domains, templates, keys, and suppression list. Pick a slug (for URLs) and a display name.

You can have multiple teams inside the same Envoi workspace — useful for dev / staging / prod isolation, or a SaaS running many end-customer tenants.

2 · Add and verify a domain

From the Domains tab, click Add domain and enter the fqdn you want to send from (e.g. acme.com or mail.acme.com). Envoi immediately generates a DKIM keypair for the domain and gives you four DNS records to set at your registrar:

MX acme.com → 10 mx.productcraft.co.
TXT acme.com → v=spf1 mx -all
TXT productcraft._domainkey.acme.com → v=DKIM1; k=rsa; p=...
TXT _productcraft-verify.acme.com → productcraft-verify=<token>

Once the records are set (propagation usually takes a few minutes), click Verify. Envoi does a live DNS lookup against the verification TXT and flips the domain to active.

3 · Write a template

In the Templates tab, click New template. Templates use Handlebars: subject and body share the same syntax. A plain-text body is optional — if omitted, we derive it from the HTML for clients that can't render rich content.

name:    welcome
subject: Welcome, {{name}}!
body:    <h1>Hi {{name}},</h1>
         <p>Thanks for signing up for Acme.</p>
         <p>Your team slug is <code>{{teamSlug}}</code>.</p>

4 · Mint an API key

From the API keys tab, click Create key. Give it a name and pick a permission scope. For a typical sender key you want:

✓ message.send
✓ template.read

The full key (starting with hdk_live_) is shown once. Copy it immediately into your secret store; if you lose it, revoke and mint a fresh one.

Keys are scoped to the current team. Even if another team gets compromised, its keys can't touch your domains, templates, or suppression list.

5 · Send

One HTTP call. :appId and :teamId come from the URL in the dashboard (visible in the address bar while you're on the team page).

curl -X POST \
  https://api.mail.productcraft.co/v1/apps/:appId/tenancies/:teamId/templates/welcome/send \
  -H "Authorization: Bearer hdk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "from": "hello@acme.com",
    "to":   "user@example.com",
    "data": { "name": "Alice", "teamSlug": "acme" }
  }'

→ HTTP/1.1 202 Accepted
{ "accepted": true, "from": "hello@acme.com", "to": "user@example.com",
  "subject": "Welcome, Alice!" }

The 202 confirms the message was rendered, DKIM-signed with your domain's private key, and queued. Delivery is async.

What else you should know

  • Rate limits. 60 sends per minute, 600 per hour, 10 000 per day per team. 429 on overflow. Contact us if you outgrow the defaults.
  • Suppression. Permanent 5xx bounces auto-populate your team's suppression list. Sends to a suppressed address return 422 before they hit the queue.
  • Invite teammates. Members tab → Invite member (email + role). They redeem the code after signing in to Heimdall. admin gets full access minus delete; member is read-only by default.
  • Render preview. Test a template before sending by hitting POST /templates/:name/render with your data payload — no mail goes out.
  • Inbound mail. Every verified domain is also listening on mx.productcraft.co. Create a mailbox, messages land with parsed MIME + attachments.

Something not covered? Open an issue or ping us — most docs gaps turn into features in the next release.