Free Transactional Email with Resend (Next.js Guide)

Send invites, password resets and notifications from a Next.js app on Resend's free tier — one fetch call, a verified domain, SPF/DKIM/DMARC, a graceful no-op when unconfigured, and what the limits mean in practice.

AAAayush AdhikariJune 29, 2026 7 min read

You can send transactional email free with Resend by calling its REST API from server code — one fetch with your API key, a from address on a domain you've verified, and the message — within the free plan's 3,000 emails a month and 100 a day. Verify your domain with SPF and DKIM (and add DMARC) so mail reaches inboxes, keep the key server-side, and make email optional: if it isn't configured or fails, the app should still work. That's how LetRelay sends invitations and password resets.

What "transactional" means

Transactional email is triggered by something a user did or needs: an invitation, a password reset, "your request was resolved", a daily digest they asked for. It's different from marketing email (newsletters, promotions), which has stricter consent and unsubscribe rules. Keep the two on separate streams — ideally separate sending addresses or subdomains — so a marketing complaint can't hurt password-reset deliverability.

Resend's free plan, in numbers

From Resend's pricing page, the Free plan includes 3,000 emails per month, 100 emails per day, 3 domains and 30-day data retention. For an internal tool, that's roughly:

  • Invitations and password resets for a few hundred users a month, comfortably.
  • Per-event notifications for a small team — if you're careful.
  • Not enough for "email every agent on every ticket update" in a busy desk. Use in-app notifications and chat webhooks for high-volume events, and email for things that must reach people outside the app. (Posting to Slack or Discord instead is covered in Slack and Discord webhooks.)

The 100-per-day cap is the one that bites first: a bulk invite of 150 people won't all go out in one day.

Sending: one fetch, no SDK

LetRelay uses Resend's REST API directly. No SDK means one less dependency and nothing that assumes a long-running server:

import "server-only";
 
export async function sendEmail({ to, subject, html }: { to: string; subject: string; html: string }) {
  const key = process.env.RESEND_API_KEY;
  if (!key) return { ok: false as const, error: "email_not_configured" };
 
  const res = await fetch("https://api.resend.com/emails", {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
    body: JSON.stringify({ from: process.env.EMAIL_FROM, to, subject, html, text: toPlainText(html) }),
  });
  if (!res.ok) {
    console.error("[email] resend error", res.status, await res.text()); // server logs only
    return { ok: false as const, error: `resend_${res.status}` };
  }
  return { ok: true as const };
}

Notes:

  • import "server-only" makes the build fail if this module is ever imported into client code, so the key can't leak into the browser bundle.
  • Never NEXT_PUBLIC_RESEND_API_KEY. Anything prefixed NEXT_PUBLIC_ ships to every visitor.
  • Include a plain-text part. Some clients show it, and messages with both parts tend to be treated better by filters.
  • Log error bodies on the server, not in the response to the user.

Graceful no-op

Email is a dependency that can be absent (a new deployment without a key), misconfigured (an unverified domain) or down. Design every email-sending flow so the core action still succeeds:

  • Invitations create the account either way. If email isn't configured or fails, the admin sees the one-time temporary password on screen to share another way. LetRelay does exactly this.
  • Password resets tell the user to contact an admin if no email arrives.
  • Notifications also appear in the in-app notification list; email is a copy, not the only channel.

Return a result ({ ok, error }) rather than throwing, and let each caller decide what "failed" means for its flow.

Domain verification and deliverability

Resend requires you to add and verify a domain before sending from it. Verification means adding DNS records that prove you control the domain and let receiving servers authenticate your mail:

  • SPF lists which servers may send for your domain.
  • DKIM signs each message so receivers can verify it wasn't altered and came from your domain.
  • DMARC tells receivers what to do when SPF/DKIM fail and where to send reports.

Google's email sender guidelines set the bar for Gmail recipients. All senders must authenticate with SPF or DKIM, keep the spam rate reported in Postmaster Tools below 0.3%, use TLS, and have valid PTR records. Bulk senders (over 5,000 messages a day to Gmail) must use SPF, DKIM and DMARC, align the From: domain with SPF or DKIM, and support one-click unsubscribe for marketing mail. A transactional sender on a free tier won't hit bulk volumes, but setting up all three from the start costs a few DNS records and avoids surprises.

Practical tips:

  • Send from a subdomain such as mail.yourdomain.com so its reputation is separate from your main domain's.
  • Use a real reply-to. "noreply" addresses frustrate people who reply with questions.
  • Keep links on your own domain. Link text that says one domain and points to another looks like phishing.

Templates that work everywhere

Email HTML is its own world: many clients ignore external CSS and modern layout. Keep templates simple:

  • Inline styles, a single column, system fonts.
  • One clear action button with a text link fallback.
  • The important information in the text, not only in images.
  • A short footer saying why they received it ("You were invited to LetRelay by Priya").

Sending credentials by email — carefully

LetRelay's invite emails include a one-time temporary password, which the person must change on first sign-in. If you do something similar:

  • Make the password single-use and force a change at first login.
  • Don't include it in the subject line (subjects show in notifications on lock screens).
  • Offer a "reset password" link as the alternative, which is often the better design.
  • Rate-limit invite and reset endpoints per IP so they can't be used to email-bomb someone — see rate limiting without Redis.

Password reset through Supabase Auth

If you use Supabase Auth, its password-reset and confirmation emails are sent by Supabase. Its built-in email service is for testing: Supabase's documentation lists a limit of 2 messages per hour (subject to change) and no delivery guarantee, and urges custom SMTP for anything beyond exploration. Configure custom SMTP in the Supabase dashboard before launch. Resend provides SMTP credentials too, so the same verified domain can send both your app's emails and Supabase's auth emails. Add your production domain to Supabase's allowed redirect URLs so reset links don't point at localhost.

Testing email

  • In development, send to your own address from a verified domain, or log the rendered HTML instead of sending.
  • In automated tests, don't send real email; assert that the flow returns the right { ok, error } and that the fallback (showing the temporary password) appears when email is off.
  • Before launch, send one of each template to Gmail, Outlook and a phone and read them there.

FAQ

Is Resend free?

Resend has a free plan with 3,000 emails per month and 100 per day on up to 3 domains, according to its pricing page. Higher volumes need a paid plan.

Do I need my own domain to send email with Resend?

Yes. Resend requires you to add and verify a domain via DNS records before sending from it, which is also what makes your mail trustworthy to receivers.

Why are my transactional emails going to spam?

Usually missing or misaligned SPF/DKIM, no DMARC record, a new domain with no reputation, or content that looks like phishing (mismatched links, image-only messages). Authenticate first, then look at content.

Should my app fail if email fails?

No. Complete the core action, show a fallback (such as the temporary password or a message to contact an admin), and log the error on the server.

Sources

AA
Aayush Adhikari

Building Relay — the internal request desk with AI triage and SLA tracking.

Run your internal requests on LetRelay

AI triage, SLA-tracked queues, and bottleneck analytics — the help desk your team actually likes. Free to start.

Try LetRelay free No credit card required
Ad spaceYour Google AdSense unit shows here once approved.

Keep reading