Skip to main content

providers/email

default()​

Overview​

The Email provider uses email to send "magic links" that can be used to sign in, you will likely have seen these if you have used services like Slack before.

Adding support for signing in via email in addition to one or more OAuth services provides a way for users to sign in if they lose access to their OAuth account (e.g. if it is locked or deleted).

The Email provider can be used in conjunction with (or instead of) one or more OAuth providers.

How it works​

On initial sign in, a Verification Token is sent to the email address provided. By default this token is valid for 24 hours. If the Verification Token is used within that time (i.e. by clicking on the link in the email) an account is created for the user and they are signed in.

If someone provides the email address of an existing account when signing in, an email is sent and they are signed into the account associated with that email address when they follow the link in the email.

tip

The Email Provider can be used with both JSON Web Tokens and database sessions, but you must configure a database to use it. It is not possible to enable email sign in without using a database.

Configuration​

  1. NextAuth.js does not include nodemailer as a dependency, so you'll need to install it yourself if you want to use the Email Provider. Run npm install nodemailer or yarn add nodemailer.
  2. You will need an SMTP account; ideally for one of the services known to work with nodemailer.
  3. There are two ways to configure the SMTP server connection.

You can either use a connection string or a nodemailer configuration object.

3.1 Using a connection string

Create an .env file to the root of your project and add the connection string and email address.

.env
    EMAIL_SERVER=smtp://username:password@smtp.example.com:587
EMAIL_FROM=noreply@example.com

Now you can add the email provider like this:

pages/api/auth/[...nextauth].js
import EmailProvider from "next-auth/providers/email";
...
providers: [
EmailProvider({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM
}),
],

3.2 Using a configuration object

In your .env file in the root of your project simply add the configuration object options individually:

.env
EMAIL_SERVER_USER=username
EMAIL_SERVER_PASSWORD=password
EMAIL_SERVER_HOST=smtp.example.com
EMAIL_SERVER_PORT=587
EMAIL_FROM=noreply@example.com

Now you can add the provider settings to the NextAuth.js options object in the Email Provider.

pages/api/auth/[...nextauth].js
import EmailProvider from "next-auth/providers/email";
...
providers: [
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: process.env.EMAIL_SERVER_PORT,
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD
}
},
from: process.env.EMAIL_FROM
}),
],
  1. Do not forget to setup one of the database adapters for storing the Email verification token.

  2. You can now sign in with an email address at /api/auth/signin.

A user account (i.e. an entry in the Users table) will not be created for the user until the first time they verify their email address. If an email address is already associated with an account, the user will be signed in to that account when they use the link in the email.

Customizing emails​

You can fully customize the sign in email that is sent by passing a custom function as the sendVerificationRequest option to EmailProvider().

e.g.

pages/api/auth/[...nextauth].js
import EmailProvider from "next-auth/providers/email";
...
providers: [
EmailProvider({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
sendVerificationRequest({
identifier: email,
url,
provider: { server, from },
}) {
// your function
},
}),
]

The following code shows the complete source for the built-in sendVerificationRequest() method:

import { createTransport } from "nodemailer";

async function sendVerificationRequest(params) {
const { identifier, url, provider, theme } = params;
const { host } = new URL(url);
// NOTE: You are not required to use `nodemailer`, use whatever you want.
const transport = createTransport(provider.server);
const result = await transport.sendMail({
to: identifier,
from: provider.from,
subject: `Sign in to ${host}`,
text: text({ url, host }),
html: html({ url, host, theme }),
});
const failed = result.rejected.concat(result.pending).filter(Boolean);
if (failed.length) {
throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`);
}
}

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>
`;
}

// Email Text body (fallback for email clients that don't render HTML, e.g. feature phones)
function text({ url, host }: { url: string, host: string }) {
return `Sign in to ${host}\n${url}\n\n`;
}
tip

If you want to generate great looking email client compatible HTML with React, check out https://mjml.io

Customizing the Verification Token​

By default, we are generating a random verification token. You can define a generateVerificationToken method in your provider options if you want to override it:

pages/api/auth/[...nextauth].js
providers: [
EmailProvider({
async generateVerificationToken() {
return "ABC123"
}
})
],

Normalizing the email address​

By default, Auth.js will normalize the email address. It treats values as case-insensitive (which is technically not compliant to the RFC 2821 spec, but in practice this causes more problems than it solves, eg. when looking up users by e-mail from databases.) and also removes any secondary email address that was passed in as a comma-separated list. You can apply your own normalization via the normalizeIdentifier method on the EmailProvider. The following example shows the default behavior:

EmailProvider({
// ...
normalizeIdentifier(identifier: string): string {
// Get the first two elements only,
// separated by `@` from user input.
let [local, domain] = identifier.toLowerCase().trim().split("@");
// The part before "@" can contain a ","
// but we remove it on the domain part
domain = domain.split(",")[0];
return `${local}@${domain}`;

// You can also throw an error, which will redirect the user
// to the sign-in page with error=EmailSignin in the URL
// if (identifier.split("@").length > 2) {
// throw new Error("Only one email allowed")
// }
},
});
danger

Always make sure this returns a single e-mail address, even if multiple ones were passed in.

default(config: EmailConfig): EmailConfig

Parameters​

ParameterType
configEmailConfig

Returns​

EmailConfig


EmailConfig​

The Email Provider needs to be configured with an e-mail client. By default, it uses nodemailer, which you have to install if this provider is present.

You can use a other services as well, like:

Custom email service with Auth.js

Properties​

id​

id: string

Uniquely identifies the provider in AuthConfig.providers It's also part of the URL

Inherited from​

CommonProviderOptions.id

name​

name: string

The provider name used on the default sign-in page's sign-in button. For example if it's "Google", the corresponding button will say: "Sign in with Google"

Inherited from​

CommonProviderOptions.name

sendVerificationRequest​

sendVerificationRequest: Function

Type declaration​

Documentation

(params: SendVerificationRequestParams): Awaitable<void>

Parameters​
ParameterType
paramsSendVerificationRequestParams
Returns​

Awaitable<void>

from?​

from: string

Default​

"Auth.js <no-reply@authjs.dev>"

generateVerificationToken?​

generateVerificationToken: Function

Type declaration​

By default, we are generating a random verification token. You can make it predictable or modify it as you like with this method.

Example​
Providers.Email({
async generateVerificationToken() {
return "ABC123";
},
});

Documentation

(): Awaitable<string>

Returns​

Awaitable<string>

maxAge?​

maxAge: number

How long until the e-mail can be used to log the user in, in seconds. Defaults to 1 day

Default​
86400;

normalizeIdentifier?​

normalizeIdentifier: Function

Type declaration​

Normalizes the user input before sending the verification request.

⚠️ Always make sure this method returns a single email address.

Note​

Technically, the part of the email address local mailbox element (everything before the @ symbol) should be treated as 'case sensitive' according to RFC 2821, but in practice this causes more problems than it solves, e.g.: when looking up users by e-mail from databases. By default, we treat email addresses as all lower case, but you can override this function to change this behavior.

Normalizing the email address | RFC 2821 | Email syntax

(identifier: string): string

Parameters​
ParameterType
identifierstring
Returns​

string

secret?​

secret: string

If defined, it is used to hash the verification token when saving to the database .