Email SDK
Adapters

SendGrid

Send through the Twilio SendGrid Mail Send API with the fullest field support of any adapter.

The SendGrid adapter calls the Twilio SendGrid Mail Send API with plain fetch. It supports every EmailMessage field: recipients land in a personalizations entry, metadata becomes custom_args, and tags become categories.

SendGrid logo
SendGrid
@opencoredev/email-sdk/sendgrid
OfficialNot API testedRequest tested
Open website

Configure

Create an API key with Mail Send permission in the SendGrid dashboard and verify the sender identity or domain you use in from.

lib/email.ts
import { createEmailClient } from "@opencoredev/email-sdk";
import { sendgrid } from "@opencoredev/email-sdk/sendgrid";

export const email = createEmailClient({
  adapters: [sendgrid({ apiKey: process.env.SENDGRID_API_KEY! })],
});

Prop

Type

Send

Everything maps: cc, bcc, headers, attachments, tags, metadata, and even multiple replyTo addresses (sent as reply_to_list). sendAt schedules the send natively as send_at (a Unix timestamp in seconds); SendGrid accepts at most 72 hours in the future.

const result = await email.send({
  from: "Acme <security@acme.com>",
  to: [{ email: "user@example.com", name: "Ada" }],
  subject: "Reset your password",
  html: "<p>Click the link below to reset your password.</p>",
  text: "Use the link below to reset your password.",
  metadata: { userId: "user_123", flow: "password-reset" },
  tags: [{ name: "type", value: "password-reset" }],
});

console.log(result.id); // SendGrid message id from the x-message-id header

SendGrid's send endpoint returns 202 Accepted with an empty body, so the adapter reads result.id from the x-message-id response header. metadata values arrive in SendGrid event webhooks as custom_args; tag values arrive as categories.

Batch sends with recipient variables

Pass recipientVariables and the adapter emits one personalizations entry per recipient with SendGrid substitutions, so one API call personalizes every recipient (up to 1000, SendGrid's personalizations cap). SendGrid substitutes %recipient.key% tokens in subject, html, and text on its side:

await email.send({
  from: "Acme <hello@acme.com>",
  to: ["ada@example.com", "linus@example.com"],
  subject: "Hi %recipient.name%",
  html: '<a href="https://acme.com/unsub?id=%recipient.id%">Unsubscribe</a>',
  recipientVariables: {
    "ada@example.com": { name: "Ada", id: "u_1" },
    "linus@example.com": { name: "Linus", id: "u_2" },
  },
});

Verify from the CLI

SENDGRID_API_KEY="SG...." npx email-sdk doctor --adapter sendgrid
SENDGRID_API_KEY="SG...." npx email-sdk send \
  --adapter sendgrid \
  --from "Acme <hello@acme.com>" \
  --to user@example.com \
  --subject "SendGrid smoke test" \
  --text "It works" \
  --dry-run

Drop --dry-run for one real send. SendGrid account review and sender verification can block delivery even when the payload validates, and only a live send proves they are done.

On this page