send0
Migration Guides

Migrate from SendGrid

Step-by-step guide to migrate from SendGrid to send0.

Overview

SendGrid's API has grown complex over the years. send0 provides a cleaner, modern API with simpler authentication and better developer experience.

1. Install the SDK

Replace @sendgrid/mail with send0:

# Before
npm install @sendgrid/mail

# After
npm install send0

Python:

# Before
pip install sendgrid

# After
pip install send0

Go:

# Before
go get github.com/sendgrid/sendgrid-go

# After
go get github.com/send0/send0-go

2. Update the client

TypeScript:

// Before (SendGrid)
import sgMail from '@sendgrid/mail';
sgMail.setApiKey('SG.xxx');

// After (send0)
import { Send0 } from 'send0';
const send0 = new Send0('sk_live_...');

Python:

# Before (SendGrid)
from sendgrid import SendGridAPIClient
sg = SendGridAPIClient("SG.xxx")

# After (send0)
from send0 import Send0
client = Send0("sk_live_...")

Go:

// Before (SendGrid)
client := sendgrid.NewSendClient("SG.xxx")

// After (send0)
client := send0.New("sk_live_...")

3. Update send calls

SendGrid's personalizations pattern is replaced by a simpler flat structure.

TypeScript:

// Before (SendGrid)
await sgMail.send({
  to: 'user@example.com',
  from: 'hello@acme.com',
  subject: 'Welcome',
  html: '<p>Hello</p>',
  categories: ['onboarding'],
  customArgs: { user_id: '123' },
});

// After (send0)
await send0.emails.send({
  from: 'hello@acme.com',
  to: 'user@example.com',
  subject: 'Welcome',
  html: '<p>Hello</p>',
  tags: { category: 'onboarding' },
  metadata: { user_id: '123' },
});

Python:

# Before (SendGrid)
from sendgrid.helpers.mail import Mail
message = Mail(
    from_email="hello@acme.com",
    to_emails="user@example.com",
    subject="Welcome",
    html_content="<p>Hello</p>",
)
sg.send(message)

# After (send0)
client.emails.send(
    from_address="hello@acme.com",
    to="user@example.com",
    subject="Welcome",
    html="<p>Hello</p>",
)

Go:

// Before (SendGrid)
from := mail.NewEmail("Acme", "hello@acme.com")
to := mail.NewEmail("User", "user@example.com")
message := mail.NewSingleEmail(from, "Welcome", to, "Hello", "<p>Hello</p>")
client.Send(message)

// After (send0)
client.Emails.Send(ctx, &send0.SendEmailParams{
    From:    "Acme <hello@acme.com>",
    To:      []string{"user@example.com"},
    Subject: "Welcome",
    HTML:    "<p>Hello</p>",
})

4. Batch sending

SendGrid uses personalizations for per-recipient data. send0 uses a dedicated batch endpoint.

// Before (SendGrid)
await sgMail.send({
  personalizations: [
    { to: 'jane@example.com', dynamicTemplateData: { name: 'Jane' } },
    { to: 'john@example.com', dynamicTemplateData: { name: 'John' } },
  ],
  from: 'hello@acme.com',
  templateId: 'd-xxx',
});

// After (send0)
await send0.emails.batch({
  from: 'hello@acme.com',
  subject: 'Monthly Update',
  template: 'tmpl_monthly',
  recipients: [
    { to: 'jane@example.com', variables: { name: 'Jane' } },
    { to: 'john@example.com', variables: { name: 'John' } },
  ],
});

5. Templates

SendGrid uses dynamic templates with Handlebars. send0 supports both server-side templates with {{variable}} syntax and JSX email components.

// Server-side template
const template = await send0.templates.create({
  name: 'welcome',
  subject: 'Welcome, {{name}}!',
  html: '<h1>Hello {{name}}</h1><p>Welcome to {{company}}.</p>',
});

// Use in a send
await send0.emails.send({
  from: 'hello@acme.com',
  to: 'user@example.com',
  subject: 'Welcome!',
  template: template.id,
  data: { name: 'Jane', company: 'Acme' },
});

6. Webhook migration

Replace SendGrid's Event Webhook with send0's webhook endpoints.

// send0 webhook verification
import { Send0 } from 'send0';

const event = Send0.webhooks.verify(
  requestBody,
  requestHeaders,
  'whsec_...',
);

switch (event.type) {
  case 'email.delivered':
    // handle delivery
    break;
  case 'email.bounced':
    // handle bounce
    break;
}

7. Event type mapping

SendGrid eventsend0 event
processedemail.queued
deliveredemail.delivered
openemail.opened
clickemail.clicked
bounceemail.bounced
spamreportemail.complained
droppedemail.failed

8. Concept mapping

SendGrid conceptsend0 equivalent
API key (SG.xxx)API key (sk_live_...)
Marketing ContactsContacts with tags
Dynamic TemplatesTemplates ({{variable}} syntax)
Sender AuthenticationDomain verification (DKIM + SPF)
PersonalizationsBatch recipients
CategoriesTags
Custom ArgsMetadata
SuppressionsSuppression list
IP Access ManagementIP allowlists on API keys
Subuser / API Key PermissionsRestricted keys with scopes

9. Feature comparison

FeatureSendGridsend0
Transactional emailYesYes
Marketing emailYes (complex setup)Yes (simple category: 'marketing')
Batch sendVia personalizationsDedicated /v1/emails/batch endpoint
ContactsYes (complex)Yes (simple CRUD + batch upsert)
TemplatesDynamic templates (Handlebars){{variable}} + JSX components
WebhooksEvent Webhook (no signatures)HMAC-SHA256 signed webhooks
Test-mode API keysNoYes (sk_test_… never delivers)
CLINoYes (send0 emails send, events tail, …)
API key scopesYes (complex)Yes (simple scope strings)
Audit logNoYes
Free tier100/day3,000/month
Pricing modelComplex tiersSimple per-send pricing