emails.sh vs SendGrid

SendGrid, owned by Twilio, sends at huge scale with marketing tools attached. emails.sh is smaller, quicker to integrate, and receives mail too.

Transactional email APIs · SendGrid claims checked July 2026

What SendGrid is

SendGrid is the incumbent. It was acquired by Twilio in 2019 and now sits inside the Twilio product line, which is why the docs, the console, and the billing feel like a communications platform rather than a small tool. It sends at a scale nobody else in this list matches, it has Marketing Campaigns alongside the Email API, it supports subusers and dedicated IPs and IP pools, and it has an integration in essentially every language and platform. Its free plan is a low daily allowance, around 100 emails a day, which is where most people first meet it.

Where SendGrid is the better choice

Pick SendGrid if you are sending at genuine scale, need subaccounts for customers or business units, want dedicated IPs with explicit pool control, or already buy Twilio and would rather have one vendor and one invoice. Enterprise procurement, SOC 2 packets, and named account management are things a large organisation needs and a small provider cannot offer credibly.

Where emails.sh differs

The complaint about SendGrid is rarely that it fails to send. It is the console, the account model, and the amount of product you have to walk past to get one message out. Here there is one endpoint, one key format, one dashboard page per message, and an integration path an assistant can complete without you reading anything. We also receive mail, which SendGrid does through inbound parse webhooks that hand you a POST body and leave the rest to you.

01

One product, not a platform

POST /v1/emails, a key that starts with esh_, and a domain screen. There are no subusers to configure before you can send, no separate marketing product sharing your navigation, and no choice to make between the API and the platform console.

02

Inbound that stores and threads

SendGrid Inbound Parse posts the parsed message to a URL you host and that is the end of its involvement. We keep the message, thread it against the send that prompted it, and give you a reply endpoint, so a support conversation is queryable rather than reassembled from your own logs.

03

An install path an assistant can walk

Every page on this site is also markdown at the same URL plus .md, there is an /llms.txt index, and there is a skill for Cursor and Claude Code. An assistant integrating SendGrid has to pick its way through a docs site written for humans and a large surface area of legacy endpoints.

Side by side

Every row is a claim we could defend with their documentation open beside it. Where they are ahead, the row says so.

Pricing shape
emails.sh Per email sent, in monthly volume bands. Domains, API keys, and seats are not billed separately.
SendGrid Volume tiers for the Email API, plus contact-based pricing for Marketing Campaigns.
Free tier
emails.sh 3,000 emails a month, 100 a day, no card, sending from your own verified domain.
SendGrid A low daily allowance, historically around 100 emails a day.
Sending domains
emails.sh One screen: add the domain, copy SPF, DKIM, and return-path records, watch them go green. Unlimited domains on every plan.
SendGrid Domain authentication via CNAMEs, with link branding as a separate step.
Deliverability posture
emails.sh Shared pools separated by send type, bounce and complaint tripwires below the thresholds that get senders suspended, dedicated IP on request.
SendGrid Enormous scale, dedicated IPs, IP pools, and a deliverability consulting arm.
Receiving mail
emails.sh Inbound MX, parsed MIME, and In-Reply-To threading, so a reply arrives as part of a conversation you can query rather than as a raw webhook body.
SendGrid Inbound Parse posts the parsed message to your URL. No storage or threading.
Logs and retention
emails.sh Every message searchable in the dashboard and readable at GET /v1/emails/:id, with its delivery, bounce, and complaint events attached.
SendGrid Activity feed with retention by plan, and an events API.
Templates
emails.sh Send html and text in the request, or store a template and reference it by id. No visual builder, because the markup belongs in your repo next to the code that sends it.
SendGrid Dynamic templates with a visual editor and Handlebars substitution.
SDKs and frameworks
emails.sh Nine clients (node and typescript, python, php, ruby, go, rust, java, .net, elixir) plus curl, and framework guides from Next.js to Laravel, Rails, and Django.
SendGrid Official libraries across every mainstream language, long established.
Marketing and lifecycle
emails.sh Audiences, segments, scheduled broadcasts, and automations, on the same verified domains and the same delivery log as your transactional mail, and on a reputation pool that is kept separate from it by force.
SendGrid Marketing Campaigns: contacts, lists, segments, Single Sends, and drip Automation with waits and exit criteria. A separate product with its own contact-tier pricing.
Webhooks
emails.sh email.delivered, email.bounced, and email.complained, each signed with x-emailssh-signature so you can verify the body before you act on it.
SendGrid A signed Event Webhook covering the full delivery lifecycle.
Path for a coding agent
emails.sh Every page served as markdown at the same path plus .md, an /llms.txt index of the whole site, and a Cursor and Claude Code skill you install once.
SendGrid Large human docs site with a long tail of legacy endpoints.
Support
emails.sh Email support on every plan including the free one, answered by the people who wrote the API. We are small, and that cuts both ways.
SendGrid Tiered, with paid plans buying faster response and account contacts.

You do not have to rewrite the personalizations array

emails.sh serves a SendGrid-compatible API that takes their v3 mail/send body, personalizations array and all, and answers the way theirs does: 202 with an empty body and the id in X-Message-Id. Errors come back as {"errors":[{"message","field","help"}]}, which is what their SDKs deserialise. Their auth scheme is already ours, so the key just changes from SG. to esh_ and no line of your send code moves.

The entire change
// The order matters, and getting it wrong fails silently.
// setApiKey resets baseUrl to api.sendgrid.com, so set the key FIRST.
sgMail.setApiKey('esh_live_yourkey');
sgMail.client.setDefaultRequest('baseUrl', 'https://api.emails.sh/sendgrid/');

All seven of their SDKs are overridable and none reads an environment variable, so this is a code change rather than a config change, though a one-line one in every language but Node. A message with several personalizations becomes a batch here, capped at 100 against their 1000. Sandbox mode, bypass_list_management, unsubscribe groups, click tracking, and legacy substitutions are refused with a message naming what to use instead, never ignored: silently dropping a bypass flag or an unsubscribe group would mail somebody who should not have been mailed. Import all five suppression lists before you send anything.

Read the migration chapter

Moving from SendGrid

The compatibility endpoint handles the code. The rest is untangling whatever account structure grew around it over the years, and `npx @emails.sh/cli migrate sendgrid` does the mechanical part: it reads all five suppression lists, your authenticated domains, event webhooks, and templates, prints a plan, and waits for a yes.

  1. 01

    Import all five suppression lists first

    Before anything else, and this is the step that is not reversible. SendGrid keeps one idea in five places: bounces, blocks, spam_reports, invalid_emails, and the global unsubscribes list. A migration that reads only bounces leaves the spam complaints behind, which are the suppressions that matter most. Mailing an address that already complained is the fastest way to get a new domain filtered.

  2. 02

    Inventory what is actually sending

    Before you touch code, list the API keys, subusers, and any Marketing Campaigns sends. Transactional mail moves here cleanly. If Marketing Campaigns is doing real work for a marketing team, keep it or move it somewhere built for campaigns rather than assuming this replaces it.

  3. 03

    Point the SDK here, key first

    Set the API key, then the base URL, in that order, because setApiKey overwrites the base URL and does it without an error. If you would rather move properly, install @emails.sh/sdk: one personalization becomes flat to, cc, and bcc, and the content array becomes html and text.

  4. 04

    Republish domain authentication

    SendGrid's domain authentication publishes CNAMEs pointing at its infrastructure. Ours are separate records, so add them alongside and leave SendGrid's in place until you have cut over. Your domain reputation stays with the domain, so there is no warm-up to redo.

  5. 05

    Move event webhooks, then Inbound Parse

    Point your Event Webhook consumer at our delivered, bounced, and complained events and verify x-emailssh-signature instead of SendGrid's signature. If you use Inbound Parse, change the MX record last, since mail can only route to one destination.

Questions

Can I keep using the SendGrid SDK?

Yes. We serve a SendGrid-compatible API at https://api.emails.sh/sendgrid that takes their v3 mail/send body, personalizations array and all, and answers 202 with the id in X-Message-Id exactly as theirs does. Their auth is already ours, so the key changes from SG. to esh_ and the send code does not move. All seven of their SDKs can be pointed at a different host; none reads an environment variable for it. In Node, set the API key before the base URL: setApiKey overwrites the base URL and does it silently.

What is the first thing to do when migrating?

Import the suppression lists, all five of them, before you send a single message. SendGrid splits one idea across bounces, blocks, spam_reports, invalid_emails, and the global unsubscribes list, and a migration that reads only bounces leaves the spam complaints behind. `npx @emails.sh/cli migrate sendgrid` reads all five, deduplicates them, and writes them to your list here first. Every other step can be undone; mailing people who already filed a complaint cannot.

Who owns SendGrid?

Twilio, which acquired it in 2019. It is sold as Twilio SendGrid and shares Twilio's account and billing model. That is a plus if you already use Twilio and a source of friction if email is the only thing you need.

What is the SendGrid free tier limit?

A small daily cap, historically about 100 emails a day, rather than a monthly pool. Check their pricing page for the current terms. Ours is 3,000 a month with a 100 a day cap, which is the same daily ceiling with a monthly total you can actually spend.

Can emails.sh replace Marketing Campaigns?

Partly, and it depends who uses it. There are audiences, segments, scheduled broadcasts, and automations with waits and branches, all as API resources and all in the dashboard. There is no drag-and-drop design editor, no A/B testing, and no signup form builder. A developer-run lifecycle programme moves cleanly; a marketing team working in the Campaigns designer does not.

Is migrating risky for deliverability?

The domain carries the reputation, so authenticating the same domain here and sending the same content to the same list is a much smaller change than it feels. Run both in parallel, shift a percentage at a time, and watch your bounce and complaint rates rather than a vendor dashboard score.

Looking for a SendGrid alternative?

These products all send an HTTP request and put a message in an inbox, and any of them will do that competently. The choice comes down to what surrounds the send: what the logs tell you at 2am, whether replies come back, and how long it takes an assistant to write working code against the API on the first try.

The free tier is 3,000 emails a month, 100 a day, no card, sending from your own verified domain, with delivery logs, webhooks, and inbound included. Enough to run real traffic through it before you decide.

More Transactional email APIs