Sending Your First Email With Resend’s API (Node.js, From Zero to Delivered)

Resend has become the default answer to “which email API should a new project use,” and after wiring it into three products I understand why: the setup is short, the SDK is clean, and the failure modes are legible. This is the walkthrough I wish existed on day one — from an empty folder to a delivered email, plus the parts tutorials skip: error handling and webhooks.

Step 1: Verify your domain

Sign up and go to Domains. Add your domain and Resend gives you a small set of DNS records: DKIM keys, an SPF record under their return-path subdomain, and a DMARC helper if you do not have one yet. Paste them at your DNS provider and wait for propagation. Until your domain is verified you can only send from Resend’s test address, which is fine for this tutorial but not for production — mail from a domain you do not own cannot build any reputation. (New to these records? Our SPF/DKIM/DMARC explainer covers what each one does.)

Step 2: First send with curl

Before touching any SDK, send one message with curl. It demystifies the whole API — it is just HTTPS with JSON:

curl -X POST 'https://api.resend.com/emails' \
  -H 'Authorization: Bearer re_ABC123' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "[email protected]",
    "to": ["[email protected]"],
    "subject": "First send",
    "html": "<p>It works.</p>"
  }'

A 200 response with an email ID means it is handed off. If you get a 403 mentioning a test address, your domain verification has not propagated yet — give it a few minutes.

Step 3: The Node SDK in your app

npm install resend
import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function sendWelcome(to, name) {
  const { data, error } = await resend.emails.send({
    from: 'MyApp <[email protected]>',
    to,
    subject: 'Welcome to MyApp',
    html: '<p>Hi ' + name + ', great to have you.</p>',
    text: 'Hi ' + name + ', great to have you.',
  });
  if (error) throw new Error(error.message);
  return data.id;
}

Three habits worth adopting immediately: always include a plain-text part alongside HTML (spam filters and screen readers both thank you); store the returned email ID with your request context so support tickets map to messages; and treat error as a first-class result, not an exception path — Resend returns structured errors you can branch on.

Two developers typing on laptops across a marble table
Two developers typing on laptops across a marble table

Step 4: Handle bounces with webhooks

APIs tell you about the handoff; webhooks tell you what happened after. In the dashboard, register a webhook URL for bounce and complaint events. Two rules: respond to the ping quickly and process asynchronously, and verify the signing secret on every request — anyone who finds your endpoint should not be able to feed it fake events. This one afternoon of work is the difference between “email probably works” and an alerting setup that tells you when a customer’s mail is not arriving.

Common early mistakes

  • Sending from a free-mail from-address like gmail.com — verify a domain, always.
  • Skipping the text part of multipart mail.
  • Hardcoding the API key instead of an environment variable, then leaking it in a repo.
  • Ignoring throttling errors on batch sends. Back off and retry with jitter; the API is telling you its limits.

Where to go next

Once basic sending works, add templates (Resend pairs with React Email for versioned, component-based templates), then wire in the webhook events you care about. If you are still choosing a provider, our Resend vs SendGrid comparison and the four-way field test cover the alternatives with the same hands-on tone. And warm up your volume gradually — the domain warmup guide applies to API providers too.

Leave a Comment