Saas Custom Emails

There is one more improvement we can do to our authentication system, and that is the magic link email we send to the user. By default, it looks like this:

Verification Email

Sending custom email using Resend

Again, we are going to use Resend for this job. First, you need to install the resend package, which allows us to send emails programmatically.

bash
1npm install resend

However, there is one small problem here. Because the Resend provider from Auth.js and the resend package we just installed have the same name. To avoid conflict in the program, we'll import the Resend package as ResendClient.

libs/auth.js

javascript
1. . .
2
3// The Resend provider from Auth.js, used to integrate Auth.js with Resend
4import Resend from "next-auth/providers/resend";
5
6// The Resend client from Resend, used to send emails
7import { Resend as ResendClient } from "resend";
8
9. . .

And then initialize the Resend client with the same API key we used before:

javascript
1. . .
2
3// The Resend provider from Auth.js, used to integrate Auth.js with Resend
4import Resend from "next-auth/providers/resend";
5
6// The Resend client from Resend, used to send emails
7import { Resend as ResendClient } from "resend";
8
9const resend = new ResendClient(process.env.AUTH_RESEND_KEY);
10
11. . .

Then in the Auth.js configurations where we configure the Resend provider, specify a sendVerificationRequest option like this:

javascript
1. . .
2
3export const { handlers, signIn, signOut, auth } = NextAuth({
4  adapter: PrismaAdapter(prisma),
5  providers: [
6    Resend({
7      sendVerificationRequest: async ({ identifier: email, url }) => {
8        await resend.emails.send({
9          from: "no-reply@send.thedevspace.io",
10          to: email,
11          subject: "Sign in to Your App",
12          html: `<a href="${url}">Sign in</a>`,
13        });
14      },
15    }),
16  ],
17  pages: {
18    verifyRequest: "/check-your-email",
19  },
20});

By default, when the user tries to sign in (send a verification request), a default verification email will be sent, but the sendVerificationRequest option allows you to customize this behavior.

This option accepts a callback function with two input arguments, identifier and url. The identifier is the user email address, which is where the verification email should be delivered to, and the url is the magic link that will be embedded into the email content.

javascript
1async ({ identifier: email, url }) => {
2  await resend.emails.send({
3    from: "no-reply@send.thedevspace.io",
4    to: email,
5    subject: "Sign in to Your App",
6    html: `<a href="${url}">Sign in</a>`,
7  });
8},

Inside the callback function, we'll send the email using the send() method provided by the Resend client.

The send() method requires you to provide the from, to, subject and html.

html defines the email content, which as you can imagine, is a piece of HTML code. To keep things simpler, we’ve stripped away all unnecessary content and only kept the magic link.

Save the changes and try to sign in again, and you should receive the following email:

Custom Verification Email

Using a email template

We were able to customize the email, but as you can see, this method requires us to write raw HTML and CSS code, which can be a lot of trouble, especially when there's no proper syntax highlighting.

Instead, we can use a email template. Resend supports React Email, which allows us to create emails just like creating React components.

As an example, create a email-template.jsx under components:

text
1src
2├── app
3│   ├── api
4│   ├── check-your-email
5│   ├── favicon.ico
6│   ├── globals.css
7│   ├── layout.jsx
8│   ├── page.jsx
9│   └── signin
10│       └── page.jsx
11├── components
12│   ├── email-template.jsx     <===== Here is your email template
13│   ├── footer.jsx
14│   └── navbar.jsx
15└── libs

The best part about using React Email is that you can use TailwindCSS inside the email template. However, since most email clients do not support CSS frameworks, we need to do things a bit differently.

Install the @react-email/components package with the following command.

bash
1npm install @react-email/components

Import the Tailwind component and make sure your entire email template is wrapped inside. This component enables you to use TailwindCSS directly.

components/email-template.jsx

jsx
1import { Tailwind } from "@react-email/components";
2
3export function EmailTemplate({ url }) {
4  return (
5    <Tailwind>
6      <div className="bg-gray-50 p-5 font-sans text-gray-800">
7        <div className="max-w-[600px] mx-auto bg-white rounded-lg shadow-lg p-6 text-center">
8          <h1 className="text-2xl font-bold mb-4 text-gray-800">
9            Welcome to Your App
10          </h1>
11          <p className="text-base leading-relaxed mb-6 text-gray-600">
12            Thank you for signing up! Please verify your email address by
13            clicking the button below:
14          </p>
15          <a
16            href={url}
17            className="inline-block bg-blue-600 text-white text-base font-bold py-3 px-6 rounded-lg no-underline mb-6">
18            Verify Email
19          </a>
20          <p className="text-sm text-gray-600 mt-4">
21            If you didn't request this email, you can safely ignore it.
22          </p>
23        </div>
24      </div>
25    </Tailwind>
26  );
27}

Lastly, go back to Auth.js configurations and replace html with react like this:

libs/auth.js

javascript
1. . .
2import { EmailTemplate } from "@/components/email-template";
3
4const resend = new ResendClient(process.env.AUTH_RESEND_KEY);
5
6export const { handlers, signIn, signOut, auth } = NextAuth({
7  adapter: PrismaAdapter(prisma),
8  providers: [
9    Resend({
10      sendVerificationRequest: async ({ identifier: email, url }) => {
11        await resend.emails.send({
12          from: "no-reply@send.thedevspace.io",
13          to: email,
14          subject: "Sign in to Your App",
15          react: EmailTemplate({ url: url }),
16        });
17      },
18    }),
19  ],
20  pages: {
21    verifyRequest: "/check-your-email",
22  },
23});

Don't forget to pass the magic link (url) to the template.

And now, try to sign in again, and you should get this email in our inbox.

Custom Verification Email with React Template