Marketing & Advertising8 min read

How to Integrate SendGrid with Your Headless CMS

Connect SendGrid to your headless CMS so publish-ready campaign content can trigger branded email sends without copy-pasting subject lines, CTAs, or article links.

Published April 29, 2026
01Overview

What is SendGrid?

Twilio SendGrid is a cloud-based email delivery platform for transactional and marketing email. Teams use it for the Mail Send API, SMTP relay, Dynamic Templates, contact lists, unsubscribe groups, suppression handling, and delivery analytics. It’s widely used by SaaS, ecommerce, media, and B2B teams that need email infrastructure without running mail servers.


02The case for integration

Why integrate SendGrid with a headless CMS?

Email campaigns often fall apart in the handoff. An editor publishes a product announcement, a marketer copies the headline into SendGrid, someone else pastes the CTA URL, and a developer updates the template data. That works for one email. It gets risky when you’re sending 12 localized launch emails, 4 event reminders, and 3 lifecycle campaigns in the same week.

Connecting SendGrid to a headless CMS category setup lets campaign content start from structured fields instead of copied page text. With Sanity as the AI Content Operating System, fields like subject line, preheader, SendGrid template ID, CTA URL, audience segment, locale, and referenced article are typed in Sanity Studio and written to the Content Lake as JSON. A webhook can fire when the campaign is published, and GROQ can fetch exactly the fields SendGrid needs.

The alternative is disconnected work: exporting CSVs, pasting HTML, maintaining duplicate content in SendGrid, and finding mistakes after the email is already in inboxes. The trade-off is that you still need to own SendGrid setup, sender authentication, unsubscribe groups, suppression rules, and send safety checks. Sanity handles structured content and event triggers. SendGrid handles delivery.


03Architecture

Architecture overview

A common flow starts when an editor publishes an emailCampaign document in Sanity Studio. That publish mutation is written to the Content Lake. A Sanity webhook, filtered with GROQ to only trigger for campaign documents, calls a Function or your own API route. The server-side handler receives the webhook payload, uses @sanity/client to fetch the full campaign with GROQ, and pulls only the fields SendGrid needs: subject, preheader, Dynamic Template ID, sender, audience emails or SendGrid list ID, unsubscribe group ID, CTA, and referenced article or product data. Then it calls SendGrid’s API, usually POST /v3/mail/send through @sendgrid/mail for a send, or PUT /v3/marketing/contacts through @sendgrid/client when you’re syncing contacts. SendGrid merges the Dynamic Template data, applies suppression and unsubscribe rules, delivers the email to the end user, and records events such as processed, delivered, open, click, bounce, and unsubscribe. If you use Functions, the sync logic runs on Sanity-side content events without standing up a separate worker or cron job.


04Use cases

Common use cases

📣

Launch announcement emails

Publish a product launch in Sanity Studio, then send SendGrid Dynamic Template data with the headline, CTA, image, locale, and linked release notes.

🛒

Back-in-stock or price-drop campaigns

Use structured product content and referenced offer fields to populate SendGrid emails without rebuilding the email body by hand.

🎟️

Event reminder sequences

Trigger SendGrid sends from event content with date, location, speaker, registration link, and reminder timing controlled in Sanity Studio.

🌎

Localized campaign variants

Query the right locale with GROQ, send the matching subject, preheader, and CTA to SendGrid, and avoid mixing regions in one campaign.


05Implementation

Step-by-step integration

  1. 1

    Set up SendGrid

    Create or use a Twilio SendGrid account, authenticate your sender domain with SPF and DKIM, create an API key with Mail Send permissions, and install the SDK with npm install @sendgrid/mail. If you’re syncing contacts, also install @sendgrid/client and grant Marketing Campaigns scopes.

  2. 2

    Model campaign content in Sanity Studio

    Create an emailCampaign schema with fields such as subject, preheader, sendgridTemplateId, fromEmail, unsubscribeGroupId, audience, locale, CTA, and a reference to an article, product, or event. Keep operational fields, like testMode and approvedForSend, separate from copy fields.

  3. 3

    Create a publish trigger

    Add a Sanity webhook filtered to campaign documents, for example _type == "emailCampaign" && approvedForSend == true. Configure the webhook payload to include the document _id, then point it at a Function or API route.

  4. 4

    Fetch the exact content with GROQ

    In the handler, use @sanity/client to query the campaign and its references. GROQ lets you join the campaign to the article, product, author, or event data SendGrid needs in one request.

  5. 5

    Call SendGrid’s API

    Use @sendgrid/mail to call SendGrid’s Mail Send API with a Dynamic Template ID and dynamicTemplateData. For production sends, add guardrails for test mode, unsubscribe group ID, suppression behavior, rate limits, and duplicate webhook delivery.

  6. 6

    Test the frontend and email path

    Preview the campaign in your site or app, send a test email to an internal seed list, verify links and UTM parameters, then publish the campaign. Check SendGrid’s Activity feed for delivered, bounced, and suppressed events.


06Code

Code example

typescriptapp/api/sanity-sendgrid/route.ts
import {createClient} from '@sanity/client';
import sgMail from '@sendgrid/mail';

const sanity = createClient({
  projectId: process.env.SANITY_PROJECT_ID!,
  dataset: process.env.SANITY_DATASET!,
  apiVersion: '2025-01-01',
  token: process.env.SANITY_READ_TOKEN!,
  useCdn: false,
});

sgMail.setApiKey(process.env.SENDGRID_API_KEY!);

export async function POST(req: Request) {
  const {_id} = await req.json();

  const campaign = await sanity.fetch(`
    *[_id == $_id && _type == "emailCampaign"][0]{
      subject,
      preheader,
      sendgridTemplateId,
      fromEmail,
      unsubscribeGroupId,
      recipients,
      ctaUrl,
      article->{title, "slug": slug.current}
    }
  `, {_id});

  if (!campaign?.sendgridTemplateId || !campaign?.recipients?.length) {
    return Response.json({skipped: true});
  }

  await sgMail.send({
    from: campaign.fromEmail,
    templateId: campaign.sendgridTemplateId,
    personalizations: campaign.recipients.map((email: string) => ({
      to: [{email}],
      dynamicTemplateData: {
        subject: campaign.subject,
        preheader: campaign.preheader,
        articleTitle: campaign.article?.title,
        articleUrl: `https://example.com/articles/${campaign.article?.slug}`,
        ctaUrl: campaign.ctaUrl,
      },
    })),
    asm: {groupId: campaign.unsubscribeGroupId},
  });

  return Response.json({sent: campaign.recipients.length});
}

07Why Sanity

How Sanity + SendGrid works

Build your SendGrid integration on Sanity

Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect campaign content with SendGrid.

Start building free →

08Comparison

CMS approaches to SendGrid

CapabilityTraditional CMSSanity
Campaign-ready content structureCampaign fields are often mixed into page body content, so marketers copy subject lines, CTAs, and links into SendGrid.Schema-as-code lets you define emailCampaign fields for SendGrid template IDs, preheaders, CTAs, locales, and referenced content.
Send trigger on publishSends usually depend on plugins, RSS exports, or manual work after publishing.GROQ-filtered webhooks or Functions can react to publish mutations and call SendGrid without a polling job.
Field-level payload controlPlugins may send rendered HTML or full page data, which can include fields the email template doesn’t need.GROQ selects only the fields SendGrid needs and can join referenced article, product, event, or author data in one query.
Audience and compliance fieldsAudience IDs and unsubscribe settings are usually handled outside the content workflow.Sanity Studio can include typed fields for SendGrid list IDs, unsubscribe group IDs, test mode, and approval state with role-based access.
Multi-channel reuseEmail content often becomes a separate copy of web content, which can drift after edits.The same structured content can feed the website, app, SendGrid campaign, and AI agents from one AI Content Operating System.

09Next steps

Keep building

Explore related integrations to complete your content stack.

Ready to try Sanity?

See how Sanity's Content Operating System powers integrations with SendGrid and 200+ other tools.