Moving from Twilio SendGrid to Resend? Flags every @sendgrid/mail and sendgrid Python call, field and webhook event that has no 1:1 Resend equivalent, with the Resend line to write instead. Runs entirely in your browser — nothing is uploaded.
Same engine as the VS Code extension, byte for byte.
This page is the working piece. The full pack has everything below.
Twilio SendGrid retired its free Email API plan starting May 27, 2025. The sample order-mail.js has eight SendGrid lines that break on Resend; 18 rules check JS, TS and Python.
Twilio SendGrid's paid Essentials plan starts at $19.95 a month now that its free plan is retired; the workspace migration plan here is $29 once.
Buy the full version — $29· ReadyStack
Real numbers from this tool, line by line.

Eight SendGrid lines break on Resend in order-mail.js, a Node.js receipt mailer with a bounce webhook, and a developer moving off Twilio SendGrid gets no error from any of them.
Twilio SendGrid retired its free Email API plan starting May 27, 2025 (Twilio changelog: "Changes coming to SendGrid's Free Plan"). New accounts have had a 60-day trial since March 25, 2025, and the paid Essentials plan starts at $19.95 a month. Resend keeps a free tier of 3,000 emails a month and a send call that looks almost the same, so plenty of teams are switching.
The send call is the easy part. sgMail.send(msg) becomes resend.emails.send({...}). The trouble is the fields that have no Resend twin. They do not throw. They are dropped, and the mail behaves differently.
Resend Migration Check ran its 18 rules over the sample file and returned eight findings:
| SendGrid line | Resend fix |
|---|---|
require('@sendgrid/mail') | require('resend') |
SENDGRID_API_KEY | RESEND_API_KEY |
sgMail.setApiKey(key) | new Resend(key) |
templateId: 'd-…' | rebuild on Resend or send html |
sendAt: Unix seconds | scheduledAt: ISO string |
asm: { groupId } | dropped: keep your own list |
sandboxMode | really sent: use [email protected] |
e.event === 'bounce' | e.type === 'email.bounced' |
The migrated file, with new Resend(process.env.RESEND_API_KEY), an ISO scheduledAt, tags and a type === 'email.bounced' branch, returns zero.
sandboxMode. In SendGrid, mailSettings.sandboxMode.enable validates a message without delivering it. Resend has no such field. Keep the block after the switch and your staging environment sends real receipts to real customers. Resend's answer is test addresses such as [email protected].
asm groupId. SendGrid's unsubscribe groups (asm) stop mail to people who opted out of one kind of message. resend.emails.send has no field for it, so the group is ignored and the opted-out address gets the email. You need your own suppression check before sending.
event === 'bounce'. SendGrid's Event Webhook posts an array of objects with an event field: bounce, spamreport, deferred. Resend posts one object with a type field: email.bounced, email.complained, email.delivery_delayed. An if (e.event === 'bounce') branch never runs again, and bounced addresses stay on your list. The signature header changes too: Resend signs with Svix (svix-id, svix-timestamp, svix-signature) instead of X-Twilio-Email-Event-Webhook-Signature.
Find-and-replace swaps @sendgrid/mail for resend and setApiKey for a constructor. It does not know that sandboxMode, asm and the webhook event names have no Resend field. The code still compiles and runs. That is why each finding here names the Resend line, or says plainly that there is none.
The same rules read Python. from sendgrid import SendGridAPIClient, SendGridAPIClient(os.environ["SENDGRID_API_KEY"]) and message.send_at = 1735689600 are flagged, and a hard-coded send_at is compared with the check date you set: on 2026-09-29 that timestamp (2025-01-01) is already in the past.
Search "resend migration check" in VS Code or Open VSX and run it on the open file. The free check has no key and no limit. The full version exports a workspace-wide migration plan, file by file.
It reads JavaScript, TypeScript and Python files that call Twilio SendGrid and flags every line that breaks on Resend: the @sendgrid/mail import, SENDGRID_API_KEY, setApiKey, d- template ids, sendAt, asm unsubscribe groups, sandboxMode, the Event Webhook signature and event names such as 'bounce'. Each finding shows the Resend line to write instead, with the line number.
Node.js and Python developers who send transactional email (receipts, password resets, sign-up mail) through Twilio SendGrid and are moving to Resend, often because SendGrid retired its free Email API plan starting May 27, 2025. It suits a solo developer migrating one app or a team lead checking a repository before the API key is swapped.
Find-and-replace swaps the package name and the send call. It does not see that sandboxMode, asm unsubscribe groups and an event === 'bounce' branch have no Resend field. That code still runs: test mail is really sent, unsubscribe groups are dropped and the bounce handler never fires, so nothing errors while mail goes wrong.
The free check runs on the open file with all 18 rules, no key and no limit, and lists every SendGrid line with its Resend replacement. The full version, $29 once, scans the whole workspace and exports one migration plan that maps every SendGrid use to its Resend replacement file by file, so the whole switch can be planned and reviewed.
Twilio SendGrid's paid Essentials plan starts at $19.95 a month now that the free plan is retired; new accounts only get a 60-day trial. Resend keeps a free tier of 3,000 emails a month. The file check here is free, and the workspace migration plan is a one-time $29 licence key per person or team seat.
One question, answered by the person who built it. Your email only if you want the answer sent.