Documentation Index: Fetch llms.txt first to discover every published page. This page is also available as Markdown at /node-sdk-receiving-email.md.
Verified · 8/11/2026

Receiving Inbound Email

Turn a raw inbound webhook delivery into a normalized ReceivedEmail object with primitive.receive, ready to pass straight into client.reply or client.forward.

primitive.receive(...), the root export of @primitivedotdev/sdk, verifies an inbound webhook delivery and returns a ReceivedEmail: a normalized object with a stable shape you can act on immediately, instead of the raw email.received event. Call it at the top of any handler that receives inbound mail, whether that's a Next.js route, an Express endpoint, or a Primitive Function.

Receive from a standard Request#

Pass the Request straight to primitive.receive when your framework hands you a Fetch API Request object, as Next.js App Router and Cloudflare Workers do. This overload is async.

  1. 1

    Install the SDK and set your webhook secret#

    npm install @primitivedotdev/sdk
    export PRIMITIVE_WEBHOOK_SECRET=whsec_...
    
  2. 2

    Call primitive.receive with the request and your secret#

    import primitive from "@primitivedotdev/sdk";
    
    export const runtime = "nodejs";
    export const maxDuration = 300;
    
    const client = primitive.client({
      apiKey: process.env.PRIMITIVE_API_KEY!,
    });
    
    export async function POST(req: Request) {
      const email = await primitive.receive(req, {
        secret: process.env.PRIMITIVE_WEBHOOK_SECRET!,
      });
    
      await client.reply(email, "Thank you for your email.");
    
      return Response.json({ ok: true });
    }
    
  3. 3

    Verify the result#

    primitive.receive(...) reads the request body, verifies the HMAC-SHA256 signature against your account secret, and resolves to a ReceivedEmail. It rejects a delivery whose timestamp is more than 300 seconds off your clock, and a tampered or expired delivery throws instead of returning. See Node.js SDK Errors for the error types and what triggers each one.

Receive from a raw body and headers#

Pass { body, headers, secret } when your framework doesn't expose a standard Request object, for example a plain Node HTTP handler or Express with express.raw({ type: "application/json" }).

import primitive from "@primitivedotdev/sdk";

const email = primitive.receive({
  body: req.body, // string or Buffer, exact bytes as received
  headers: req.headers,
  secret: process.env.PRIMITIVE_WEBHOOK_SECRET!,
});

This overload is synchronous and returns a ReceivedEmail directly, not a Promise. body must be the exact bytes of the HTTP request before any JSON parsing; a body that has been parsed and re-serialized will fail signature verification on insignificant whitespace alone.

Tip

Only need to verify a signature without normalizing the payload? Use verifyWebhookSignature from @primitivedotdev/sdk/webhook directly. See Webhook Signature Verification.

The ReceivedEmail shape#

ReceivedEmail is the flat, normalized shape primitive.receive(...) returns, with the sender, recipient, subject, body, and threading fields promoted to the top level:

email.sender.address;
email.sender.name;

email.receivedBy;
email.receivedByAll;

email.replyTarget.address;
email.replySubject;
email.forwardSubject;

email.subject;
email.text;

email.thread.messageId;
email.thread.references;

email.raw;
FieldDescription
sender.address, sender.nameThe From address, parsed leniently for display. Falls back to the SMTP envelope sender when the header can't be parsed, so it is not a safe authorization anchor. See Verifying Inbound Email Authenticity.
receivedByThe recipient address this email was received on.
receivedByAllEvery recipient address on the delivery.
replyTarget.addressThe Reply-To address when the inbound email carried one, otherwise the sender. Fully sender-controlled, so never authorize on it.
replySubjectThe Re: <parent> subject client.reply uses.
forwardSubjectThe Fwd: <parent> subject client.forward uses.
subjectThe original inbound subject line.
textThe plain-text body, when present.
thread.messageId, thread.referencesThreading headers used to derive In-Reply-To and References on replies.
rawThe full, schema-validated email.received event this object was normalized from.

Use email.raw whenever you need something outside the normalized shape: the original headers, SPF/DKIM/DMARC results, attachment metadata, or the raw MIME download URL.

Note

Hand email straight to client.reply(email, ...) or client.forward(email, ...); see Sending, Replying, and Forwarding Email for both. Recipients, subject, and threading headers on a reply are derived server-side from the inbound row the email's id points to, not recomputed client-side.

Next steps#

Was this page helpful?

© Primitive SDKs

Powered by Browzer