Stop 14 · Payments & Third-Party IntegrationsTopics · 2/6

Email Services (Resend/SendGrid)

Part of the Full Stack Developer Roadmap

In short

Password resets, receipts, welcome mails: users expect them in seconds, in the inbox, not spam. An email API plus a verified domain gets you there with a few lines of backend code.

Sending transactional emails (welcome, password reset, receipts) from your backend using a dedicated email API instead of trying to send mail directly, which gets flagged as spam.

The blob character presses a rubber stamp onto a sealed envelope beside a pile of envelopes.

Think of it like this

The official stamp

A letter on college letterhead with the principal's stamp gets read. A plain pamphlet from nobody goes in the dustbin. Email works the same way: services like Resend or SendGrid send from your verified domain with signatures that inboxes trust, so your mail looks official.

Watch it happen

A password reset email

Browser
Your API
Email API
Inbox

POST /forgot-password

1/6The user types their email on the reset page.

The big ideas

What you need to know

Verify your domain

Add the SPF and DKIM DNS records the provider gives you. Without them, mail lands in spam or bounces.

Send from the backend

API keys stay on the server. The frontend asks your API, and your API calls the email service.

Don't block the request

For heavy sends, put the email in a job queue so a slow provider doesn't slow down your API response.

Same reply for every email

On reset requests, always say 'if an account exists, we've sent a link', so nobody can check who's registered.

See it in code

Walk through the code

ts
1import { Resend } from "resend";2const resend = new Resend(process.env.RESEND_API_KEY);3 4export async function sendResetEmail(to: string, resetUrl: string) {5  const { data, error } = await resend.emails.send({6    from: "MyShop <no-reply@mail.myshop.in>",7    to,8    subject: "Reset your MyShop password",9    html: `<p>Click <a href="${resetUrl}">this link</a> to reset your password. It expires in 30 minutes.</p>`,10    text: `Reset your password: ${resetUrl} (expires in 30 minutes)`,11  });12  if (error) throw new Error(`Reset email failed: ${error.message}`);13  return data?.id;14}

1/3The API key comes from a backend environment variable, never from frontend code.

SendGrid's @sendgrid/mail package has the same shape: set an API key, then send { to, from, subject, html }.

Save yourself the pain

Common mistakes

Oops

Sending mail 'from' a gmail.com address through your API.

Do this instead

Send from a domain you own and have verified. Inboxes distrust a server claiming to be Gmail.

Oops

Storing the raw reset token in the database.

Do this instead

Store only a hash of the token with an expiry, and delete it once used, just like a password.

Your mission

Send a real reset email

~30 min

Quick check

Why should POST /forgot-password give the same reply whether or not the email is registered?

Go deeper

  1. 1Send a welcome email from your backend when a user signs up.
  2. 2Build an HTML email template for a password reset flow.
  3. 3Learn why dedicated email services handle deliverability far better than a raw SMTP call.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge