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.
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.
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.
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.
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.
Step-by-step integration
- 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
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
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
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
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
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.
Code example
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});
}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 →CMS approaches to SendGrid
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Campaign-ready content structure | Campaign 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 publish | Sends 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 control | Plugins 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 fields | Audience 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 reuse | Email 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. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Google Ads
Use structured landing page and product content to keep ad copy, campaign URLs, and promotion data aligned.
Sanity + HubSpot
Connect campaign content with CRM segments, lead forms, lifecycle stages, and follow-up workflows.
Sanity + Mailchimp
Send newsletter and campaign content from structured fields into Mailchimp audiences, templates, and journeys.