Skip to content
All docs pages

Send with Node

You’ll need a project in Console (ask the platform team for one), and Node 18 or later.

1. Make a key

In Console, open your project’s API keys page and make a test key with Sending only. Test keys never send to anyone, so you can try everything here safely. Keep it in an environment variable:

Terminal
export HERALD_API_KEY=hrld_test_…

2. Install the SDK

Terminal
npm install @heraldmail/sdk

It has no dependencies, and runs on Node, Deno, Bun and edge runtimes.

3. Send

send.ts
import { Herald } from '@heraldmail/sdk'

const herald = new Herald(process.env.HERALD_API_KEY)

const { data, error } = await herald.emails.send(
  {
    from: 'Mentor <hello@mentor.app>',
    to: 'ada@example.com',
    subject: 'Your sign-in link',
    html: '<p>Sign in to Mentor: <a href="https://mentor.app/s/8Fq2">continue</a></p>',
    text: 'Sign in to Mentor: https://mentor.app/s/8Fq2',
  },
  { idempotencyKey: 'sign-in/8Fq2' },
)

if (error) throw new Error(`${error.name}: ${error.message}`)
console.log('Accepted', data.id)

from must be on a domain the project has added; with a live key, a verified one (see Domains and DNS). Every call answers { data, error }: exactly one is set, and an API error is never thrown.

The idempotency key makes the send safe to retry: if your process dies after Herald accepted it, sending again with the same key returns the first answer, and it’s still one email. Use something that identifies the email in your own app.

4. See what happened

In test mode the email is in your project’s Test inbox in Console straight away. From code:

TypeScript
const { data: email } = await herald.emails.get(data.id)
console.log(email.status, email.events.map((e) => e.type))

An email’s status moves from queued to sent, then to delivered, delayed, bounced or complained. A recipient who unsubscribed, bounced or complained before is suppressed, and isn’t sent to. Rather than polling, ask Herald to tell you: see Webhooks.

5. Go live

When it works, verify the domain, make a live key and send for real. A new project can send 1,000 recipients a day until the platform team approves it; live Proclamations also need the domain’s DMARC record.

Templates, batches and more

TypeScript
// a published template, by id, filled in with variables
await herald.emails.send({ to: 'ada@example.com', template: { id: 'f1c…', variables: { name: 'Ada' } } })

// up to 100 at once: all accepted, or none
await herald.emails.batch([{ from, to: 'ada@example.com', subject, text }, { from, to: 'grace@example.com', subject, text }])

// every email you've sent, a page at a time
for await (const e of herald.emails.all()) console.log(e.id, e.status)

The SDK covers the whole API: domains, keys, webhooks, contacts, topics, lists, segments, templates, broadcasts, automations and inbound mail. Its methods follow the API reference.