Notideus
Tutorials

Sending emails with Node.js

A complete Node.js walkthrough with the official SDK: sending, error handling and retries.

Use the official notideus — zero dependencies, Node 18 and later:

npm install notideus

The send function

emails.send authenticates with your API key, throws a typed NotideusError on failure, and resolves with the stored email row:

import { Notideus } from 'notideus';

const notideus = new Notideus(process.env.NT_KEY); // "nt_live_…"

const email = await notideus.emails.send({
  from: 'Notideus <noreply@demo.dev>',
  to: ['jane@example.com'],
  subject: 'Welcome to Notideus',
  html: '<p>Hi Jane,</p><p>Your account is ready.</p>',
  idempotency_key: 'docs-quickstart-1'
});

console.log(email.id, email.status);

Expected output

send resolves with the stored email row (201 Created). Response abbreviated to id, status, from, to and subject:

{
  "id": "01a0a11c-188e-7c9e-9b69-753fcb4c8d0d",
  "status": "queued",
  "from_address": "Notideus <noreply@demo.dev>",
  "to_emails": ["jane@example.com"],
  "subject": "Welcome to Notideus"
}

id uniquely identifies this email; status is queued — it is picked up for delivery from there.

Error handling

The SDK throws NotideusError, which carries the API error code, the HTTP status, and retryAfter (seconds) on 429. Catch it and branch on err.code:

import { Notideus, NotideusError } from 'notideus';

try {
  await notideus.emails.send({
    from: 'Notideus <noreply@demo.dev>',
    to: ['jane@example.com'],
    subject: 'Welcome to Notideus',
    html: '<p>Hi Jane,</p><p>Your account is ready.</p>'
  });
} catch (err) {
  if (err instanceof NotideusError) {
    console.error(err.code, err.status, err.message);
  }
}
StatusCodeWhat to do
401unauthorizedMissing, invalid or revoked key — check NT_KEY.
403insufficient_scopeThe key lacks emails:send — create a key with the right scope.
402quota_exceededMonthly allowance reached — back off and retry later. See Quotas and limits.
422from_domain_not_verifiedThe From domain matches no verified team domain — verify it in the dashboard first.
The SDK retries idempotent sends for you: it re-issues a request on network failure, 5xx or 429 (honoring Retry-After) only when the send carries an idempotency_key — so a retried send never double-sends. Choosing the key is still yours: derive it from your own data (for example order-12345-welcome). See Idempotency for key choice and scope rules.
Copyright © 2026