Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@bernierllc/email-sendgrid-plugin

mkbernier0SEE LICENSE IN LICENSE1.0.1TypeScript support: included

SendGrid-specific template management, sender verification, and advanced features plugin for email template service

sendgrid, email, template, plugin, sender-verification, template-management

readme

@bernierllc/email-sendgrid-plugin

SendGrid-specific template management, sender verification, and advanced features plugin for email template services.

Installation

npm install @bernierllc/email-sendgrid-plugin

Overview

This package provides a comprehensive plugin for integrating SendGrid's template management and sender verification features into your email template service. It includes:

  • Template CRUD Operations - Create, read, update, and delete SendGrid templates
  • Verified Sender Management - Manage and validate SendGrid verified senders
  • Template Synchronization - Bi-directional sync between local and SendGrid templates
  • Safety Features - Shared account protection and template ownership validation
  • Rate Limiting - Built-in API rate limiting to respect SendGrid quotas
  • Template Versioning - Support for SendGrid template versions and activation

Key Features

Template Management

  • Full CRUD operations with SendGrid API
  • Template versioning and activation
  • Shared account safety (application-scoped operations)
  • Template prefix enforcement
  • Conflict detection and resolution

Verified Sender Integration

  • Sender verification status checking
  • Domain matching and validation
  • Automatic sender selection
  • Sender configuration management

Safety and Security

  • Application-scoped operations (never access non-app templates)
  • Template prefix enforcement
  • Shared account protection
  • Operation auditing and logging
  • Strict/permissive safety modes

Usage

Basic Setup

import { SendGridTemplatePlugin } from '@bernierllc/email-sendgrid-plugin';

const plugin = new SendGridTemplatePlugin({
  apiKey: process.env.SENDGRID_API_KEY!,
  templatePrefix: 'MyApp - ',
  safetyMode: 'strict',
  rateLimits: {
    templatesPerMinute: 60,
    apiCallsPerSecond: 10
  }
});

// Initialize the plugin
await plugin.initialize({});

Creating Templates

import { Template } from '@bernierllc/email-sendgrid-plugin';

const template: Template = {
  id: 'local-123',
  name: 'Welcome Email',
  subject: 'Welcome to {{appName}}',
  htmlContent: '<html><body><h1>Welcome {{userName}}</h1></body></html>',
  textContent: 'Welcome {{userName}}',
  category: 'transactional',
  tags: ['welcome', 'onboarding'],
  version: '1.0.0',
  isActive: true,
  requiredVariables: ['appName', 'userName'],
  createdAt: new Date(),
  updatedAt: new Date(),
  createdBy: 'system',
  lastModifiedBy: 'system'
};

const sendgridTemplateId = await plugin.createTemplate(template);
console.log(`Created SendGrid template: ${sendgridTemplateId}`);

Managing Templates

// Get template
const template = await plugin.getTemplate('sendgrid-template-id');

// List all templates
const templates = await plugin.listTemplates();

// Update template
await plugin.updateTemplate('sendgrid-template-id', updatedTemplate);

// Delete template
await plugin.deleteTemplate('sendgrid-template-id');

Sender Verification

// Get all verified senders
const senders = await plugin.getVerifiedSenders();

// Validate sender email
const validation = await plugin.validateSender('noreply@myapp.com');

if (!validation.isValid) {
  console.log('Sender validation failed:');
  validation.errors.forEach(error => console.log(`- ${error}`));

  console.log('Suggestions:');
  validation.suggestions.forEach(suggestion => console.log(`- ${suggestion}`));
}

// Select best sender for outgoing email
const bestSender = await plugin.selectBestSender('noreply@myapp.com');
if (bestSender) {
  console.log(`Using verified sender: ${bestSender.email}`);
}

Template Synchronization

// Sync local template to SendGrid
const syncResult = await plugin.syncToProvider(localTemplate);

if (syncResult.success) {
  console.log(`Synced template ${syncResult.action}: ${syncResult.providerTemplateId}`);
} else {
  console.error(`Sync failed: ${syncResult.error}`);
}

// Pull template from SendGrid
const localTemplate = await plugin.syncFromProvider('sendgrid-template-id');

// Batch synchronization
const results = await plugin.batchSyncTemplates([template1, template2, template3]);
const successful = results.filter(r => r.success).length;
console.log(`Batch sync: ${successful}/${results.length} successful`);

Template Versioning

// Create new template version
const versionId = await plugin.createTemplateVersion('sendgrid-template-id', {
  name: 'v2.0.0',
  subject: 'Updated Subject',
  htmlContent: '<html><body>Updated content</body></html>',
  textContent: 'Updated content',
  active: false
});

// Activate template version
await plugin.activateTemplateVersion('sendgrid-template-id', versionId);

Configuration

SendGridPluginConfig

interface SendGridPluginConfig {
  // SendGrid API key (required)
  apiKey: string;

  // Template prefix for shared account safety (required)
  templatePrefix: string;

  // Safety mode: 'strict' or 'permissive' (required)
  safetyMode: 'strict' | 'permissive';

  // Whether using shared SendGrid account (optional)
  sharedAccount?: boolean;

  // API rate limits (optional)
  rateLimits?: {
    templatesPerMinute: number;
    apiCallsPerSecond: number;
  };

  // Webhook configuration (optional)
  webhookConfig?: {
    secret: string;
    eventTypes: string[];
  };
}

Safety Modes

Strict Mode (Recommended):

  • Only allows operations on templates registered with the application
  • Throws UnauthorizedTemplateAccessError for unregistered templates
  • Provides maximum safety in shared account environments

Permissive Mode:

  • Allows operations on any template
  • Useful for administrative tools or migration scripts
  • Use with caution in shared account environments

Rate Limiting

The plugin includes built-in rate limiting to respect SendGrid's API quotas:

const plugin = new SendGridTemplatePlugin({
  apiKey: process.env.SENDGRID_API_KEY!,
  templatePrefix: 'MyApp - ',
  safetyMode: 'strict',
  rateLimits: {
    templatesPerMinute: 60,   // Max 60 template operations per minute
    apiCallsPerSecond: 10      // Max 10 API calls per second
  }
});

Plugin Capabilities

The plugin provides information about its capabilities:

// Get all capabilities
const capabilities = plugin.getCapabilities();

// Check if feature is supported
if (plugin.supportsFeature('sender-verification')) {
  console.log('Sender verification is supported');
}

// Get feature configuration
const config = plugin.getFeatureConfig('template-management');
console.log(`Supports versioning: ${config.supportsVersioning}`);

Available Capabilities

  • template-management: Full CRUD operations for SendGrid templates
  • sender-verification: SendGrid verified sender management
  • template-analytics: Template usage and performance analytics
  • batch-operations: Efficient bulk template operations

Error Handling

The plugin provides specific error types for different failure scenarios:

import {
  SendGridApiError,
  TemplateNotFoundError,
  UnauthorizedTemplateAccessError,
  TemplateConflictError,
  RateLimitError
} from '@bernierllc/email-sendgrid-plugin';

try {
  await plugin.getTemplate('template-id');
} catch (error) {
  if (error instanceof TemplateNotFoundError) {
    console.log('Template does not exist');
  } else if (error instanceof UnauthorizedTemplateAccessError) {
    console.log('Template not owned by this application');
  } else if (error instanceof SendGridApiError) {
    console.log(`SendGrid API error: ${error.statusCode}`);
  } else if (error instanceof RateLimitError) {
    console.log('Rate limit exceeded');
  }
}

Integration with Email Template Service

This plugin is designed to work with @bernierllc/email-template-service:

import { SendGridTemplatePlugin } from '@bernierllc/email-sendgrid-plugin';
import { EmailTemplateService } from '@bernierllc/email-template-service';

const sendGridPlugin = new SendGridTemplatePlugin({
  apiKey: process.env.SENDGRID_API_KEY!,
  templatePrefix: 'MyApp - ',
  sharedAccount: true,
  safetyMode: 'strict',
  rateLimits: {
    templatesPerMinute: 60,
    apiCallsPerSecond: 10
  }
});

const templateService = new EmailTemplateService({
  providers: [sendGridPlugin],
  syncConfig: {
    enabled: true,
    providers: {
      sendgrid: {
        enabled: true,
        strategy: 'auto',
        direction: 'bidirectional'
      }
    }
  }
});

await templateService.initialize();

Testing

Run the test suite:

# Run tests in watch mode
npm test

# Run tests with coverage
npm run test:coverage

# Run tests once
npm run test:run

API Reference

SendGridTemplatePlugin

Core Methods

  • initialize(config: PluginConfig): Promise<void> - Initialize the plugin
  • destroy(): Promise<void> - Cleanup and destroy the plugin

Template Operations

  • createTemplate(template: Template): Promise<string> - Create a new template
  • updateTemplate(id: string, template: Template): Promise<void> - Update existing template
  • deleteTemplate(id: string): Promise<void> - Delete a template
  • getTemplate(id: string): Promise<ProviderTemplate> - Get template by ID
  • listTemplates(): Promise<ProviderTemplate[]> - List all templates

Sender Operations

  • getVerifiedSenders(): Promise<VerifiedSender[]> - Get all verified senders
  • validateSender(email: string): Promise<SenderValidationResult> - Validate sender email
  • selectBestSender(email: string): Promise<VerifiedSender | null> - Auto-select best sender

Synchronization

  • syncToProvider(template: Template): Promise<SyncResult> - Sync template to SendGrid
  • syncFromProvider(id: string): Promise<Template> - Pull template from SendGrid
  • batchSyncTemplates(templates: Template[]): Promise<SyncResult[]> - Batch sync

Versioning

  • createTemplateVersion(id: string, version: TemplateVersion): Promise<string> - Create version
  • activateTemplateVersion(id: string, versionId: string): Promise<void> - Activate version

Capabilities

  • getCapabilities(): ProviderCapability[] - Get all capabilities
  • supportsFeature(feature: string): boolean - Check feature support
  • getFeatureConfig(feature: string): FeatureConfig | null - Get feature config

Integration Status

  • Logger: Optional - All SendGrid operations and safety events
  • Docs-Suite: Ready - Complete API documentation
  • NeverHub: Optional - SendGrid API health monitoring and template sync events

NeverHub Integration

This package supports optional NeverHub integration for enhanced observability and event-driven workflows:

import { SendGridTemplatePlugin } from '@bernierllc/email-sendgrid-plugin';
import { NeverHubAdapter } from '@bernierllc/neverhub-adapter';

const plugin = new SendGridTemplatePlugin({
  apiKey: process.env.SENDGRID_API_KEY!,
  templatePrefix: 'MyApp - ',
  safetyMode: 'strict'
});

// Auto-detect NeverHub availability
const neverhub = await NeverHubAdapter.detectNeverHub()
  ? new NeverHubAdapter()
  : null;

if (neverhub) {
  // Register plugin capabilities
  await neverhub.register({
    type: 'email-plugin',
    name: '@bernierllc/email-sendgrid-plugin',
    capabilities: ['template-management', 'sender-verification']
  });

  // Subscribe to template events
  await neverhub.subscribe('template.updated', async (event) => {
    await plugin.syncFromProvider(event.templateId);
  });
}

await plugin.initialize({});

The plugin works fully without NeverHub integration - all core functionality is available regardless of NeverHub presence.

Dependencies

  • @sendgrid/mail - Official SendGrid SDK
  • @bernierllc/logger - Operation logging (optional)
  • @bernierllc/retry-policy - API call retries
  • @bernierllc/rate-limiter - API rate limiting

License

Copyright (c) 2025 Bernier LLC. All rights reserved.

See Also