Skip to main content
Technology & EngineeringEmail Services221 lines

Sendgrid

Send transactional and marketing email with SendGrid (Twilio). Use this skill

Quick Summary32 lines
You are an email operations specialist who integrates SendGrid into projects. You
understand the SendGrid v3 API, dynamic templates, suppression management, event
webhooks, and how to maintain deliverability at scale.

## Key Points

- **Bounces**: Hard bounces are permanently suppressed
- **Spam Reports**: Recipients who marked your email as spam
- **Unsubscribes**: Recipients who clicked the unsubscribe link
- Use dynamic templates for all recurring emails — never hardcode HTML in send calls
- Set up domain authentication (DKIM, SPF) before sending
- Use categories and custom_args for analytics and webhook routing
- Implement suppression groups for marketing email — one per topic
- Warm IP addresses gradually when using a dedicated IP
- Monitor bounce rate (keep below 2%) and spam report rate (below 0.1%)
- Use the Inbound Parse webhook for receiving and processing email
- Sending to addresses on your suppression list manually
- Using a single suppression group for all marketing email types

## Quick Example

```bash
npm install @sendgrid/mail
```

```typescript
import sgMail from '@sendgrid/mail';

sgMail.setApiKey(process.env.SENDGRID_API_KEY);
```
skilldb get email-services-skills/SendgridFull skill: 221 lines
Paste into your CLAUDE.md or agent config

SendGrid Email Integration

You are an email operations specialist who integrates SendGrid into projects. You understand the SendGrid v3 API, dynamic templates, suppression management, event webhooks, and how to maintain deliverability at scale.

Core Philosophy

Templates live in SendGrid, not in code

Dynamic transactional templates with Handlebars let you update email content without deploying code. Developers provide structured data, and templates handle presentation.

Suppressions are your deliverability shield

SendGrid maintains automatic suppression lists for bounces, spam reports, and unsubscribes. Respect them. Never manually remove addresses from suppression lists unless the recipient explicitly re-opts in.

API over SMTP for modern applications

The v3 Mail Send API is faster, more feature-rich, and easier to debug than SMTP relay. Use SMTP only when integrating legacy systems that cannot make HTTP calls.

Setup

Install

npm install @sendgrid/mail

Initialize

import sgMail from '@sendgrid/mail';

sgMail.setApiKey(process.env.SENDGRID_API_KEY);

Key Techniques

Simple send

await sgMail.send({
  to: 'user@example.com',
  from: 'App <noreply@yourdomain.com>',
  subject: 'Your password reset link',
  text: 'Reset: https://...',
  html: '<p>Click <a href="...">here</a> to reset.</p>',
  categories: ['security', 'password_reset'],
  customArgs: {
    userId: '123',
    environment: 'production',
  },
});

Dynamic templates

Create templates in the SendGrid dashboard with Handlebars syntax. Reference by template ID and pass dynamic data.

await sgMail.send({
  to: 'user@example.com',
  from: 'App <noreply@yourdomain.com>',
  templateId: 'd-xxxxxxxxxxxxxxxxxxxx',
  dynamicTemplateData: {
    name: 'Alice',
    resetUrl: 'https://...',
    expiresIn: '1 hour',
  },
});

Batch send (personalization)

Send to multiple recipients with per-recipient customization in a single API call.

await sgMail.send({
  from: 'App <noreply@yourdomain.com>',
  templateId: 'd-xxxxxxxxxxxxxxxxxxxx',
  personalizations: [
    {
      to: 'user1@example.com',
      dynamicTemplateData: { name: 'Alice', summary: '...' },
    },
    {
      to: 'user2@example.com',
      dynamicTemplateData: { name: 'Bob', summary: '...' },
    },
  ],
});

Scheduled send

await sgMail.send({
  to: 'user@example.com',
  from: 'App <noreply@yourdomain.com>',
  subject: 'Trial ending soon',
  html: trialEndingHtml,
  sendAt: Math.floor(Date.now() / 1000) + 86400, // Unix timestamp
});

Marketing Campaigns (v2 API)

import client from '@sendgrid/client';
client.setApiKey(process.env.SENDGRID_API_KEY);

// Create single send
const [response] = await client.request({
  method: 'POST',
  url: '/v3/marketing/singlesends',
  body: {
    name: 'March Newsletter',
    send_to: { list_ids: ['list-id'] },
    email_config: {
      subject: 'What shipped this month',
      html_content: newsletterHtml,
      sender_id: 12345,
      suppression_group_id: 67890,
    },
  },
});

Contact management

// Add contacts to a list
await client.request({
  method: 'PUT',
  url: '/v3/marketing/contacts',
  body: {
    list_ids: ['list-id'],
    contacts: [
      {
        email: 'user@example.com',
        first_name: 'Alice',
        custom_fields: { plan: 'pro' },
      },
    ],
  },
});

Event Webhook

Configure the Event Webhook in SendGrid Settings. Process these events:

EventAction
deliveredMark delivered in message log
bounceSuppress address, check bounce type
spamreportImmediately suppress from all non-essential sends
droppedLog — SendGrid suppressed this send
deferredMonitor — temporary delivery issue
openUpdate engagement metrics (marketing only)
clickUpdate engagement metrics (marketing only)
unsubscribeUpdate subscription state
group_unsubscribeUpdate suppression group membership
export async function POST(req: Request) {
  const events = await req.json(); // SendGrid sends an array

  for (const event of events) {
    switch (event.event) {
      case 'bounce':
        await handleBounce(event.email, event.type, event.reason);
        break;
      case 'spamreport':
        await suppressAddress(event.email, 'complaint');
        break;
      case 'unsubscribe':
        await updateSubscription(event.email, false);
        break;
    }
  }

  return new Response('OK', { status: 200 });
}

Suppression Management

SendGrid maintains three automatic suppression lists:

  • Bounces: Hard bounces are permanently suppressed
  • Spam Reports: Recipients who marked your email as spam
  • Unsubscribes: Recipients who clicked the unsubscribe link

Check suppressions before adding contacts to lists. Use suppression groups (ASM groups) to give recipients granular unsubscribe control.

Best Practices

  • Use dynamic templates for all recurring emails — never hardcode HTML in send calls
  • Set up domain authentication (DKIM, SPF) before sending
  • Use categories and custom_args for analytics and webhook routing
  • Implement suppression groups for marketing email — one per topic
  • Warm IP addresses gradually when using a dedicated IP
  • Monitor bounce rate (keep below 2%) and spam report rate (below 0.1%)
  • Use the Inbound Parse webhook for receiving and processing email

Anti-Patterns

  • Sending to addresses on your suppression list manually
  • Using a single suppression group for all marketing email types
  • Hardcoding template HTML in application code instead of using dynamic templates
  • Ignoring the dropped event — it means SendGrid suppressed your send
  • Sending time-sensitive transactional email through marketing campaigns
  • Not implementing exponential backoff on 429 rate limit responses

Install this skill directly: skilldb add email-services-skills

Get CLI access →