New from emailrHealthCheck Email iconHealthCheck Email
emailr_

Send email from Next.js with emailr_

Send transactional email from Next.js App Router route handlers and server actions with the emailr_ SDK, and verify delivery webhooks safely.

Next.js iconNext.jsFramework

The emailr SDK is a small, fetch-based TypeScript client, so it fits naturally into Next.js route handlers and server actions. This guide sets up sending from the App Router and receiving signed delivery events.

Keep the API key on the server: never import the client into a Client Component or expose the key with a NEXT_PUBLIC_ prefix.

Set up emailr_ with Next.js

  1. 01

    Create an API key

    Create a key under API keys in the dashboard. Keys start with et_live_ and are scoped to one domain workspace. Store it as EMAILR_API_KEY in your secret manager or environment, never in client-side code.

  2. 02

    Add and verify your sending domain

    In the dashboard, open Domains and add the domain you send from. A subdomain such as mail.yourcompany.com keeps transactional reputation separate from your corporate mailbox.

    Emailr generates the DNS records: a DKIM TXT record on the emailr._domainkey selector, an SPF TXT record, and an MX + TXT pair on the send subdomain used as the MAIL FROM / Return-Path. A DMARC record is optional but recommended.

    Emailr's DKIM selector and send subdomain don't collide with other providers' records, so you can add them before cutting over and send from both providers during the migration. A domain can only have one SPF record: if one already exists, merge Emailr's include: into it instead of adding a second record.

  3. 03

    Install the SDK and add your key

    Install the package and add EMAILR_API_KEY to .env.local locally and to your hosting provider's environment settings in production.

    Terminalbash
    npm install emailr
  4. 04

    Create a shared client

    Create the client once in a server-only module. Install the server-only package; importing it makes the build fail if a Client Component ever imports this file.

    lib/emailr.tsts
    import 'server-only'
    import { Emailr } from 'emailr'
    
    export const emailr = new Emailr({ apiKey: process.env.EMAILR_API_KEY! })
  5. 05

    Send from a route handler

    Route handlers are the right place for sends triggered by API calls or third-party services. emails.send() resolves to { success, message_id, recipients, status } and throws an EmailrError (with statusCode and code) when the API rejects the request.

    app/api/welcome/route.tsts
    import { emailr } from '@/lib/emailr'
    
    export async function POST(request: Request) {
      const { email, name } = await request.json()
    
      const result = await emailr.emails.send({
        from: 'Acme <[email protected]>',
        to: email,
        subject: `Welcome, ${name}`,
        html: `<p>Hi ${name}, thanks for signing up.</p>`,
        tags: { category: 'welcome' },
      })
    
      return Response.json({ id: result.message_id })
    }
  6. 06

    Or send from a server action

    For forms, a server action avoids writing an API route at all.

    app/contact/actions.tsts
    'use server'
    
    import { emailr } from '@/lib/emailr'
    
    export async function sendContactMessage(formData: FormData) {
      await emailr.emails.send({
        from: 'Website <[email protected]>',
        to: '[email protected]',
        reply_to_email: String(formData.get('email')),
        subject: 'New contact form message',
        text: String(formData.get('message')),
      })
    }
  7. 07

    Receive delivery events

    Create a transactional webhook in the dashboard pointing at /api/webhooks/emailr. Read the body with request.text() so the signature is computed over the exact bytes that were sent, then parse it.

    app/api/webhooks/emailr/route.tsts
    import { createHmac, timingSafeEqual } from 'node:crypto'
    
    export async function POST(request: Request) {
      const body = await request.text()
      const signature = request.headers.get('x-emailr-signature') ?? ''
      const expected = createHmac('sha256', process.env.EMAILR_WEBHOOK_SECRET!)
        .update(body)
        .digest('hex')
    
      if (signature.length !== expected.length ||
          !timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
        return new Response('Invalid signature', { status: 401 })
      }
    
      const { event, data } = JSON.parse(body)
      if (event === 'email.bounced') {
        // mark the address as undeliverable in your database
      }
      return new Response('ok')
    }

Tips

  • React Email or any other renderer works: render to an HTML string first and pass it as html.
  • The webhook route uses node:crypto, so keep it on the Node.js runtime (the default).
  • For bulk newsletters use Broadcasts instead of looping over emails.send() in a request.

Frequently asked questions

Does the emailr_ SDK work with the Next.js App Router?

Yes. Use it in route handlers, server actions and other server-only code. It uses fetch under the hood and has no native dependencies.

Can I send email from a Client Component?

No. Sending requires your secret API key, which must stay on the server. Call a server action or route handler from the client instead.

Can I use React Email templates?

Yes. Render the component to an HTML string and pass it as the html field, or store the markup as an emailr_ template and send it with template_id and template_data.

How do I handle bounces in Next.js?

Subscribe a transactional webhook to your route handler, verify the X-Emailr-Signature header against the raw body, and handle email.bounced and email.complained events.

Start sending in minutes

Create a free account, verify your domain and send your first email. No credit card required.