Sendardocs
Jump to content
All guides

Send email with Next.js

A server route handler that sends on demand — your key never reaches the browser. Allow additional time for domain verification.

Download the starter projects · View on GitHub · Check your email domain

Before you start

  1. 1

    Create a free account

    Sign up at sendar.app — the Free plan includes 3,000 emails a month (100/day) with no card and no expiry.

  2. 2

    Verify your sending domain

    On the Domains page, add the domain you'll send from and create the DNS records it shows you. Verification usually completes within minutes of the DNS propagating.

  3. 3

    Create an API key

    On the API Keys page, create a key. It's shown once — copy it somewhere safe. Keys look like sndr_… and go in the Authorization header.

Send your first email

Replace the API key and the from domain with your own — the from address must use the domain you verified.

lib/demo.mjs — local development only
// Local demonstration only. Do not expose this endpoint as a production mail service.
export async function handleDemo(request, env=process.env, send=fetch) {
 if(env.NODE_ENV!=='development')return Response.json({error:'Demo disabled in production'}, {status:404});
 const origin=request.headers.get('origin');
 let localOrigin=false;
 try {const u=new URL(origin);localOrigin=u.protocol==='http:'&&['localhost','127.0.0.1'].includes(u.hostname)&&u.host===request.headers.get('host');} catch {}
 if(!localOrigin)return Response.json({error:'Same-origin local requests only'}, {status:403});
 const payload={from:env.SENDAR_FROM||'hello@example.com',to:[env.SENDAR_TO||'reader@example.net'],subject:'Your booking is confirmed',text:'Demo booking: 12 October, 10:00 UTC. Reference DEMO-123.'};
 if(env.SENDAR_SEND!=='1')return Response.json({mode:'preview',message:'No email sent. Configure a verified sender and controlled recipient before enabling live sending.',payload});
 if(!env.SENDAR_API_KEY||!env.SENDAR_FROM||!env.SENDAR_TO)return Response.json({error:'Configure SENDAR_API_KEY, SENDAR_FROM and SENDAR_TO'}, {status:400});
 try {
  const response=await send('https://sendar.app/api/emails',{method:'POST',headers:{Authorization:`Bearer ${env.SENDAR_API_KEY}`,'Content-Type':'application/json'},body:JSON.stringify(payload),signal:AbortSignal.timeout(15000)});
  const data=await response.json();
  if(!response.ok)return Response.json({error:`Sendar returned HTTP ${response.status}. Inspect your email log before retrying.`},{status:502});
  return Response.json({mode:'live',id:data.id,status:data.status,message:'Inspect the Sendar email log and recipient inbox. Acceptance does not guarantee delivery.'});
 } catch {return Response.json({error:'Outcome uncertain. Inspect your Sendar email log before trying again.'},{status:502});}
}

Use the complete Next.js project in the starter download. It includes the route handler, page, environment example and tests. Preview mode makes no external request.

Run the complete App Router starter

Download and unzip the starter bundle. From its nextjs directory, use Node 20.9 or newer and run the commands below. Open http://127.0.0.1:3000 and click Run configured demo.

terminal
npm ci
cp .env.example .env.local
npm run dev

Expected preview result

The response contains mode: preview and your message payload. No account or API key is required for preview, and no email is sent. The key is never returned to the browser.

Illustrative response (trimmed)
{"mode":"preview","payload":{"from":"hello@example.com","to":["reader@example.net"],"subject":"Your booking is confirmed"}}

Enable one controlled send

After verifying your domain, configure SENDAR_API_KEY, SENDAR_FROM and SENDAR_TO in .env.local. Use a recipient you control. Set SENDAR_SEND=1, restart the local server and click once. Save the returned ID and check the Sendar email log and inbox before another attempt.

Before using this in a real application

The demo route is disabled in production. Put the send inside an authenticated business-event handler, authorise recipients from server records, validate inputs and add rate limits and durable event deduplication. Never accept arbitrary recipient addresses from a public browser form.

What a successful request means

A successful response includes the message ID and status. Save the ID and inspect it in the email log. Provider acceptance does not guarantee inbox delivery. Use a recipient you control for your first test.

Choose a real workflow

For a booking confirmation, include the agreed time, time zone and booking reference. For a receipt, use a confirmed payment event. For password resets, generate expiring single-use tokens in your application; Sendar transports the email and does not issue authentication tokens.

Handle errors without duplicate messages

Keep credentials server-side. Correct invalid requests before retrying. If a timeout leaves acceptance uncertain, inspect the email log before submitting the message again. Add application-level deduplication around payment and booking events.

Run the starter project

Download the starter bundle linked below for Node, Python and a Next.js server-action example. Each runs in preview mode by default. Use your own verified sender and controlled recipient when you explicitly enable live sending.

Check the result

A successful live send returns an email object; a status of sent means provider acceptance. Open the Emails page in your dashboard to see the send, its recipient, and its delivery status — provider acceptance does not guarantee inbox delivery.

If something goes wrong

CodeMeaningFix
401Missing or invalid API keyCheck the Authorization header is exactly `Bearer sndr_...` with a key from the API Keys page.
403Sending domain not verifiedThe domain in your `from` address must be added and verified (DNS records) on the Domains page first.
422Invalid request bodyProvide `from`, at least one `to` recipient, a `subject`, and `html` or `text`. The error message names the exact field.
429Plan quota reachedYou've hit your plan's monthly or daily cap (Free: 3,000/month, 100/day). Upgrade on the Pricing page or wait for the window to reset.

Where to next

  • Batch sending — POST /emails/batch delivers up to 100 emails in one request — see the API docs.
  • Scheduling — Add scheduledAt (ISO 8601) to send up to 30 days in the future (Growth plan and above).
  • Webhooks — Get notified of delivery events instead of polling — configured on the Webhooks page.
  • Pricing — 3,000 emails/month free; paid plans from $12 for 30,000 — flat caps, no overage billing.

Ready when you are.

3,000 emails a month free — no card required.

Create your account
Need a hand with your integration?Contact Sendar