Migrate from SendGrid
letr.dev as a SendGrid alternative, with API keys, DNS records, webhook events, SMTP settings and suppressions mapped for the move.
For an app that sends its sign-in codes, receipts and password links through SendGrid. letr.dev takes over that part. It sends no marketing campaigns and stores no templates.
letr.dev costs CHF 12 a month for 10'000 recipients, then CHF 0.50 per started 1'000 recipients, up to a monthly ceiling of 10'000 or 25'000 recipients that you choose; for more, letr.dev can grant a higher ceiling (limits). letr.dev counts per recipient: an email to three people counts three (overage).
Steps
- Sign up. The account goes live on payment and starts on step 0 with 50 recipients a day (daily limit). Keep SendGrid for the rest until the account has moved up.
- Add your sending domain and publish letr.dev's DKIM record next to SendGrid's records.
- Create one API key per app.
- Create a webhook endpoint for the events you use.
- Import your SendGrid suppressions.
- Point the app at letr.dev's API or SMTP relay.
- Remove SendGrid's records once SendGrid sends nothing more from the domain.
API keys
| SendGrid | letr.dev |
|---|---|
| Full Access | sending_access, the least privilege an app that sends needs; full_access only for the one-off suppression import |
| Custom Access with the Mail permission | sending_access, optionally limited to some of your domains |
| Custom Access with read scopes only | read_only: every GET under /v1 |
| Billing Access, Email Address Validation Access | None |
SendGrid's key types are described under API keys (01.11.2026); letr.dev's under API keys.
DNS records
letr.dev needs one TXT record for DKIM at letr._domainkey, and advises DMARC. Bounces return to bounces.letr.dev, so your SPF record stays as it is (DNS records). SendGrid's domain authentication publishes one of two sets; names below are relative to your domain, and the digits after em differ per account.
| SendGrid record | With letr.dev |
|---|---|
CNAME em1234 (SPF and return path) |
Not needed |
CNAME s1._domainkey and s2._domainkey (DKIM) |
Replaced by TXT letr._domainkey |
With automated security off: MX and TXT em1234 (return path, SPF), TXT m1._domainkey (DKIM) |
Not needed; DKIM moves to letr._domainkey |
TXT _dmarc |
Keep it: a record that starts with v=DMARC1 counts |
| Link branding CNAMEs, if you set them up | Not needed: letr.dev does not rewrite links |
Because the selectors differ, both providers' DKIM records can stay side by side during the switch. Remove SendGrid's once its last emails are out. Source: SendGrid's domain authentication and link branding guides, 01.11.2026.
Webhook events
| SendGrid event | letr.dev event |
|---|---|
processed |
email.sent |
delivered |
email.delivered |
deferred |
email.deferred |
bounce |
email.bounced |
bounce with type blocked |
No separate event |
dropped |
None: letr.dev refuses at once to send to a suppressed address, with 422 recipient_suppressed or, over SMTP, 550 5.1.1 |
spamreport |
email.complained |
open, click |
None: letr.dev does not track opens or clicks |
unsubscribe, group_unsubscribe, group_resubscribe |
None: letr.dev keeps no unsubscribe lists |
| Account status change | No direct match: account.paused and account.reactivated follow letr.dev's auto-pause, a failed payment or a pause by letr.dev (the reason in the payload), not SendGrid's account status |
| None | email.failed: letr.dev gave up on the email |
letr.dev signs every event with the endpoint's own secret; verify the signature before you trust it. The event types say what each letr.dev event means. Source: SendGrid's Event Webhook reference, 01.11.2026.
SMTP
For code that only speaks SMTP, such as Rails, Django or WordPress, change four settings. SendGrid uses the host smtp.sendgrid.net on port 25, 2525, 587 or 465, the username apikey and an API key with the Mail permission. letr.dev uses:
| Setting | Value |
|---|---|
| Host | smtp.letr.dev |
| Port | 587 with STARTTLS (required) or 465 with implicit TLS |
| Username | letr |
| Password | An API key with sending_access |
letr.dev does not listen on ports 25 and 2525. The SMTP guide shows the settings for each framework. Source: SendGrid's SMTP integration guide, 01.11.2026.
Suppressions
SendGrid keeps one list per reason. In its console, export each as CSV under Suppressions: Bounces, Invalid Emails, Spam Reports and Global Unsubscribes. Group Unsubscribes stop only the mail of one unsubscribe group, and letr.dev has no groups: leave them out unless those people should get none of your mail. Blocks need no export: SendGrid does not suppress them either (suppressions, 01.11.2026).
letr.dev reads only the first column of each line. Make sure the email address is the first column of every file, then create a full_access key in the dashboard only for the import and import each file with it:
curl https://api.letr.dev/v1/suppressions/import \
-H "Authorization: Bearer $LETR_API_KEY" \
-H "Content-Type: text/csv" \
--data-binary @bounces.csv
An import holds at most 10'000 lines and 1 MB; split larger files. Imported addresses get the reason manual (import a list). When the import is done, revoke that key in the dashboard; revoking stops it at once. The app keeps its sending_access key. letr.dev sends nothing at all to a suppressed address, password links included, so import unsubscribes only if your transactional mail should stop for those people too.
What letr.dev does not do
- Marketing Campaigns, contact lists and newsletters: letr.dev sends transactional email only; keep a marketing tool for those.
- Dynamic templates: your app renders the email and sends the finished
htmlandtext. - Open and click tracking, link branding and unsubscribe groups.
- Email address validation.