SendDart in Next.js: Keep Email Behind an Authorized Server Action

SendDart in Next.js: Keep Email Behind an Authorized Server Action

Design a Next.js email integration with server-only credentials, authenticated actions, durable intent and delivery evidence outside rendering.

SendDart Team

TL;DR

  • Keep sending email behind an authorized server action: do not perform sends during rendering or shared data loads; define deliberate business actions that check identity, permission, and record the intent.
  • Make the mutation durable and let a worker perform the provider call: persist the invitation and its notification intent so the HTTP action can finish and a worker can reliably render and send.
  • Treat the SDK result and UI state separately: explicitly inspect API errors and preserve machine-readable diagnostics, and keep notification evidence distinct from invitation validity to avoid misleading UI or duplicate sends.

Rendering a page must not send a message

In a Next.js application, rendering, data loading and user mutations have different responsibilities. Email is an external side effect and belongs behind a deliberate authorized action. Putting a send call in page rendering or a broadly reused data loader can cause surprising behavior when the framework renders or fetches for reasons other than a new user request.

Define a business action such as inviteTeamMember or requestVerification. The server checks identity and permission, validates the target and records the intended notification. The browser receives only the information needed to explain the result to the user.

This guide describes an integration architecture, not a drop-in implementation. Match the route, runtime and deployment details to the version of Next.js you use and verify the final flow in your application.

Establish the server-only boundary

Keep the SendDart client and its credential in a module that is restricted to server execution. Do not export the client through a shared utility that Client Components can import. Next.js's data-security guidance explains why server boundaries and authorization still matter when building application actions. Next.js data security.

A Server Action is not automatically authorization for every operation it can perform. Validate the current user's permission inside the action or its trusted data-access layer. For a team invitation, derive the organization from authorized membership rather than accepting an arbitrary organization ID as sufficient proof.

Constrain the payload. The client may provide an invitee address, but it should not choose the API endpoint, From identity, template code or unrestricted attachment URL. Those choices belong to server-side configuration and business policy.

Make the mutation durable

Record the invitation or other business event together with its notification intent where practical. Returning a successful action result should mean the application has retained the intended work, not that a detached promise was started and may finish later.

A worker can load the notification, render its immutable template version and call SendDart. This lets the HTTP action finish without requiring the provider request to fit the entire user interaction. It also gives recovery a durable record if the deployment or worker stops.

If you choose synchronous sending for a small workflow, still store the operation identity and budget the request explicitly. Leave time to persist the result before the hosting environment ends execution. Avoid claiming the message reached an inbox when only API acceptance is known.

Related reading: Best Email API: Choose With a Production Acceptance Test.

Related reading: Scheduled Email Delivery: Store the Time, Content and Cancellation State.

Handle the SDK result explicitly

The SendDart Node.js SDK returns a data/error result for documented API calls. A resolved promise can contain an API error, so inspect that branch and translate it into your application's notification state. SendDart Node.js SDK.

Preserve machine-readable error details without exposing private provider diagnostics or credentials to the browser. A user may need a message such as “The invitation is queued” or “Sending is temporarily unavailable,” while operators need the specific quota or configuration reason.

Use a stable operation key for supported send recovery and keep the payload unchanged. The key should come from the stored notification, not from a fresh random value generated every time the action or worker executes.

Separate cache updates from email outcomes

After an invitation is created, the application may refresh the relevant page or invalidate cached data according to its current framework design. That UI update reflects the business record. It should not trigger another send when the page reloads.

Display notification evidence separately from invitation validity. An invitation can exist while its email is pending or rejected. A delivered notification does not mean the invited person accepted the invitation. Keeping those states distinct avoids confusing badges and incorrect automation.

For repeated form submissions, use a business-level uniqueness rule or explicit resend policy. Disabling a button is helpful interaction design but does not prevent concurrent requests, retries or another browser session from creating duplicate work.

Keep the webhook route independent

A provider callback needs its own verification path. Preserve the raw request body required by SendDart's signature verifier, authenticate the event and persist it before slow downstream processing. Do not reuse a general JSON parser if it destroys the bytes needed for verification.

Correlate the event through the stored provider message identifier and tenant ownership. A callback should not select arbitrary records based only on an untrusted organization field. Handle duplicate and early-arriving events under a defined reconciliation policy.

Keep the callback response small and its processing bounded. Template rendering, attachment scanning or lengthy analytics updates can run after authenticated evidence is retained, using the application's durable worker mechanism.

Test the browser-to-worker story

Test an authorized invitation, an unauthorized organization reference, a repeated submission and an invalid address. Assert that the browser cannot alter the sender or provider destination. Check the built client assets or relevant bundle boundary to ensure the credential remains server-only.

Then test the worker with accepted, rejected and uncertain provider outcomes. A page refresh should show the existing notification evidence without producing another send. A duplicate webhook should update one logical observation rather than create a second invitation.

Use SendDart's documented simulator recipients for a controlled integration stage, followed by a small live canary if needed. Keep those tests separate from customer traffic and label what each proves.

A good Next.js integration makes email a consequence of an authorized durable mutation. Rendering remains free of sending side effects, the UI reports honest state, and the worker owns recovery outside the lifetime of the original action.