Skip to content
Migrating from NextAuth.js v4? Read our migration guide.
Guides
Configuring Custom HTTP Email Provider

HTTP Email

We have a few built-in HTTP Email providers like Resend, SendGrid and Postmark, sometimes you may want to use your own HTTP endpoint to send emails.

To do this, we can write our own provider with a custom sendVerificationRequest method. Don’t forget, an email type provider requires a database adapter.

./auth.ts
import NextAuth from "next-auth"
import { sendVerificationRequest } from "./lib/authSendRequest"
 
export const { handlers, auth } = NextAuth({
  adapter,
  providers: [
    {
      id: "http-email",
      type: "email",
      sendVerificationRequest,
    },
  ],
})

After we’ve setup the initial configuration, you’ve got to write sendVerificationRequest function. Below is a simple version which just sends a text email with a link to the user.

./lib/authSendRequest.ts
export async function sendVerificationRequest({ identifier: email, url }) {
  // Call the cloud Email provider API for sending emails
  const response = await fetch("https://api.sendgrid.com/v3/mail/send", {
    // The body format will vary depending on provider, please see their documentation
    body: JSON.stringify({
      personalizations: [{ to: [{ email }] }],
      from: { email: "noreply@company.com" },
      subject: "Sign in to Your page",
      content: [
        {
          type: "text/plain",
          value: `Please click here to authenticate - ${url}`,
        },
      ],
    }),
    headers: {
      // Authentication will also vary from provider to provider, please see their docs.
      Authorization: `Bearer ${process.env.SENDGRID_API}`,
      "Content-Type": "application/json",
    },
    method: "POST",
  })
 
  if (!response.ok) {
    const { errors } = await response.json()
    throw new Error(JSON.stringify(errors))
  }
}

A more advanced sendVerificationRequest can be seen below, this is a version of the builtin function.

./lib/authSendRequest.ts
export async function sendVerificationRequest(params) {
  const { identifier: to, provider, url, theme } = params
  const { host } = new URL(url)
  const res = await fetch("https://api.resend.com/emails", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${provider.apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      from: provider.from,
      to,
      subject: `Sign in to ${host}`,
      html: html({ url, host, theme }),
      text: text({ url, host }),
    }),
  })
 
  if (!res.ok)
    throw new Error("Resend error: " + JSON.stringify(await res.json()))
}
 
function html(params: { url: string; host: string; theme: Theme }) {
  const { url, host, theme } = params
 
  const escapedHost = host.replace(/\./g, "​.")
 
  const brandColor = theme.brandColor || "#346df1"
  const color = {
    background: "#f9f9f9",
    text: "#444",
    mainBackground: "#fff",
    buttonBackground: brandColor,
    buttonBorder: brandColor,
    buttonText: theme.buttonText || "#fff",
  }
 
  return `
<body style="background: ${color.background};">
  <table width="100%" border="0" cellspacing="20" cellpadding="0"
    style="background: ${color.mainBackground}; max-width: 600px; margin: auto; border-radius: 10px;">
    <tr>
      <td align="center"
        style="padding: 10px 0px; font-size: 22px; font-family: Helvetica, Arial, sans-serif; color: ${color.text};">
        Sign in to <strong>${escapedHost}</strong>
      </td>
    </tr>
    <tr>
      <td align="center" style="padding: 20px 0;">
        <table border="0" cellspacing="0" cellpadding="0">
          <tr>
            <td align="center" style="border-radius: 5px;" bgcolor="${color.buttonBackground}"><a href="${url}"
                target="_blank"
                style="font-size: 18px; font-family: Helvetica, Arial, sans-serif; color: ${color.buttonText}; text-decoration: none; border-radius: 5px; padding: 10px 20px; border: 1px solid ${color.buttonBorder}; display: inline-block; font-weight: bold;">Sign
                in</a></td>
          </tr>
        </table>
      </td>
    </tr>
    <tr>
      <td align="center"
        style="padding: 0px 0px 10px 0px; font-size: 16px; line-height: 22px; font-family: Helvetica, Arial, sans-serif; color: ${color.text};">
        If you did not request this email you can safely ignore it.
      </td>
    </tr>
  </table>
</body>
`
}

To sign in via this custom provider, you would refer to it by the id in when you are calling the sign-in method, for example: signIn('http-email', { email: 'user@company.com' }).

Auth.js © Balázs Orbán and Team - 2024