# 邮件 (/docs/concepts/email)

了解如何设置邮件验证、要求登录时使用已验证的邮件地址、在验证后自动登录、处理验证后的回调，以及实现密码重置邮件。



邮件是 Better Auth 的关键部分，所有用户无论使用何种认证方式都必须使用邮件。Better Auth 开箱即用提供邮件和密码认证，并提供了很多工具帮助你管理邮件验证、密码重置等功能。

## 自带电子邮件服务商 [#自带电子邮件服务商]

Better Auth 可与任何事务性电子邮件服务商配合使用，让您完全掌控身份验证邮件的发送方式。要发送邮件，请先设置您偏好的服务商。

例如，你可以考虑以下邮件服务商：

* [Resend](https://resend.com/better-auth)
* [SuperSend TX](https://docs.supersendtx.com/guides/better-auth)
* [Mailtrap](https://docs.mailtrap.io/guides/integrations/better-auth)
* [Wraps](https://wraps.dev/docs/guides/better-auth)
* [eusend](https://eusend.dev/docs/integrations/better-auth)

## 邮件验证 [#邮件验证]

### 在你的应用中添加邮件验证 [#在你的应用中添加邮件验证]

要启用邮件验证，你需要传入一个发送验证邮件的函数，该邮件带有一个链接。

* **sendVerificationEmail**：当邮件验证启动时触发的函数。它接收一个包含以下属性的数据对象：
  * `user`：包含邮件地址的用户对象。
  * `url`：用户必须点击以验证邮件的验证链接。
  * `token`：验证令牌，用于完成邮件验证，可用于自定义验证链接的实现。

- **sendVerificationEmail**：当邮件验证启动时触发的函数。它接收一个包含以下属性的数据对象：
  * `user`：包含邮件地址的用户对象。
  * `url`：用户必须点击以验证邮件的验证 URL。
  * `token`：用于完成邮件验证的验证令牌，可在实现自定义验证 URL 时使用。

以及作为第二个参数传入的 `request` 对象。

```ts title="auth.ts"
import { betterAuth } from 'better-auth';
import { sendEmail } from './email'; // 你的邮件发送函数

export const auth = betterAuth({
    emailVerification: {
        sendVerificationEmail: async ({ user, url, token }, request) => {
            void sendEmail({
                to: user.email,
                subject: '验证你的邮件地址',
                text: `点击链接验证你的邮件：${url}`
            })
        }
    }
})
```

<Callout type="warn">
  避免等待邮件发送完成，以防止时序攻击。在无服务器平台上，请使用 `waitUntil` 或类似方法来确保邮件发送成功。
</Callout>

### 触发邮件验证 [#触发邮件验证]

你可以通过多种方式触发邮件验证：

#### 1. 注册时 [#1-注册时]

要在注册时自动发送验证邮件，请将 `emailVerification.sendOnSignUp` 设置为 `true`。

```ts title="auth.ts"
import { betterAuth } from 'better-auth';

export const auth = betterAuth({
    emailVerification: {
        sendOnSignUp: true
    }
})
```

这样用户注册时会发送验证邮件。对于社交登录，邮件验证状态会从 SSO 读取。

<Callout>
  启用 `sendOnSignUp` 后，当用户使用未声明邮件已验证的 SSO 登录时，Better Auth 会发送验证邮件，但即使启用了 `requireEmailVerification`，用户仍然无需验证邮件即可登录。
</Callout>

#### 2. 强制邮件验证 [#2-强制邮件验证]

如果启用强制邮件验证，用户必须验证邮件后才能登录。每次用户尝试登录时，都会调用 `sendVerificationEmail`。

<Callout>
  只有在实现了 `sendVerificationEmail`、将 `sendOnSignIn` 设置为 `true`，并且用户尝试使用邮件和密码登录时，此功能才会生效。
</Callout>

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { sendEmail } from './email'; // 你的邮件发送函数

export const auth = betterAuth({
  emailVerification: {
    sendVerificationEmail: async ({ user, url }) => {
      void sendEmail({
        to: user.email,
        subject: "验证你的邮件地址",
        text: `点击链接验证你的邮件：${url}`,
      });
    },
    sendOnSignIn: true,
  },
  emailAndPassword: {
    requireEmailVerification: true,
  },
});
```

如果用户尝试在未验证邮件的情况下登录，你可以捕获错误并向用户显示提示。

```ts title="auth-client.ts"
await authClient.signIn.email({
    email: "email@example.com",
    password: "password"
}, {
    onError: (ctx) => {
        // 处理错误
        if(ctx.error.status === 403) {
            alert("请验证你的邮件地址")
        }
        // 你也可以显示原始错误消息
        alert(ctx.error.message)
    }
})
```

#### 3. 手动触发 [#3-手动触发]

你也可以通过调用 `sendVerificationEmail` 手动触发邮件验证。

```ts
await authClient.sendVerificationEmail({
    email: "user@email.com",
    callbackURL: "/" // 验证后重定向的 URL
})
```

### 验证邮件 [#验证邮件]

如果用户点击验证链接，他们的邮件会被自动验证，并被重定向至 `callbackURL`。

对于手动验证，你可以发送带有 `token` 的自定义链接给用户，然后调用 `verifyEmail` 方法。

```ts
await authClient.verifyEmail({
    query: {
        token: "" // 在这里传递令牌
    }
})
```

### 验证后自动登录 [#验证后自动登录]

若你希望用户成功验证邮件后自动登录，请将 `autoSignInAfterVerification` 选项设置为 `true`：

```ts
import { betterAuth } from "better-auth";

const auth = betterAuth({
    //... 其他配置
    emailVerification: {
        autoSignInAfterVerification: true
    }
})
```

### 验证前回调 [#验证前回调]

你可以使用 `beforeEmailVerification` 回调，在用户邮件被标记为已验证之前运行自定义代码。这对于验证、预检查或在最终确定验证之前准备数据非常有用。

```ts title="auth.ts"
import { betterAuth } from 'better-auth';

export const auth = betterAuth({
    emailVerification: {
        async beforeEmailVerification(user, request) {
            // 运行验证前逻辑
            console.log(`About to verify ${user.email}`);
        }
    }
})
```

### 验证成功后回调 [#验证成功后回调]

你可以使用 `afterEmailVerification` 回调，在用户成功验证邮件后立即执行自定义代码。这对于触发副作用非常有用，比如授予特殊权限或记录日志。

`afterEmailVerification` 函数会在用户邮件确认时自动调用，接收 `user` 对象和 `request` 详情，以便你针对特定用户执行操作。

示例如下：

```ts title="auth.ts"
import { betterAuth } from 'better-auth';

export const auth = betterAuth({
    emailVerification: {
        async afterEmailVerification(user, request) {
            // 你的自定义逻辑，例如授予高级功能访问权限
            console.log(`${user.email} 已成功验证！`);
        }
    }
})
```

### 重复注册尝试回调 [#重复注册尝试回调]

当有人尝试使用已经存在的邮箱注册时，会触发 `onExistingUserSignUp` 回调。这对于通知现有用户有人尝试使用他们的邮箱地址注册非常有用。

<Callout>
  仅当 `emailAndPassword.requireEmailVerification` 设置为 `true` 时，才会调用此回调。此设置会启用通用重复响应（合成用户），而不是抛出邮箱重复错误。
</Callout>

```ts title="auth.ts"
import { betterAuth } from 'better-auth';

export const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
        onExistingUserSignUp: async ({ user }, request) => {
            // 通知现有用户有人尝试使用他们的邮箱注册
            console.log(`Someone tried to sign up with ${user.email}`);
        }
    }
})
```

## 密码重置邮件 [#密码重置邮件]

忘记密码时，重置密码功能允许用户重设密码。Better Auth 提供了简单的方式实现密码重置。

你可以通过传入发送密码重置邮件的函数来启用密码重置功能，该邮件带有一个链接。

```ts title="auth.ts"
import { betterAuth } from 'better-auth';
import { sendEmail } from './email'; // 你的邮件发送函数

export const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
        sendResetPassword: async ({ user, url, token }, request) => {
            void sendEmail({
                to: user.email,
                subject: '重置你的密码',
                text: `点击链接重置你的密码：${url}`
            })
        }
    }
})
```

<Callout type="warn">
  避免等待邮件发送完成，以防止计时攻击。在无服务器平台上，请使用 `waitUntil` 或类似机制来确保邮件能够发送。
</Callout>

更多关于如何在应用中实现密码重置的信息，请查看 [邮件和密码](/docs/authentication/email-password#请求密码重置) 指南。
你也可以参阅 [OTP 验证](/docs/plugins/email-otp#使用-otp-重置密码) 指南，了解如何用 OTP 实现密码重置。

