Even if user.emailVerified = true, calling the /send-verification-email endpoint will still send a verification email. #2794

Closed
opened 2026-03-13 10:20:36 -05:00 by GiteaMirror · 7 comments
Owner

Originally created by @shinexoh on GitHub (Jan 30, 2026).

Originally assigned to: @bytaesu on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { betterAuth, type BetterAuthOptions } from 'better-auth/minimal';

const betterAuthOptions = {
  basePath: '/auth',
  appName: envConfig.APP_NAME,
  baseURL: envConfig.BETTER_AUTH_URL,
  secret: envConfig.BETTER_AUTH_SECRET,
  trustedOrigins: envConfig.TRUSTED_ORIGINS,
  plugins: [
    admin({
      defaultRole: 'user',
      adminRoles: ['admin'],
    }),
    openAPI(),
  ],
  database: drizzleAdapter(db, {
    provider: 'pg',
    usePlural: true,
    schema,
  }),
  secondaryStorage: {
    // ...
  },
  emailAndPassword: {
    enabled: true,
    autoSignIn: true,
    requireEmailVerification: true,
    revokeSessionsOnPasswordReset: true,
    sendResetPassword: async ({ user, url }) => {
      void sendEmail({
        to: user.email,
        subject: 'Reset your password',
        html: resetPasswordTemplate({ url }),
      });
    },
    password: {
      hash: hashPassword,
      verify: async (data) => verifyPassword(data.password, data.hash),
    },
  },
  emailVerification: {
    sendOnSignIn: false,
    sendOnSignUp: false,
    expiresIn: 60 * 60 * 12,
    autoSignInAfterVerification: true,
    sendVerificationEmail: async ({ user, url }) => {
      void sendEmail({
        to: user.email,
        subject: 'Verify your email',
        html: verifyEmailTemplate({ url }),
      });
    },
    afterEmailVerification: async (user) => {
      // ...
    },
  },
  advanced: {
    cookiePrefix: envConfig.APP_NAME,
    database: {
      generateId: false,
    },
  },
  user: {
    deleteUser: {
      enabled: true,
      sendDeleteAccountVerification: async ({ user, url }) => {
        // ...
      },
    },
  },
  session: {
    expiresIn: 60 * 60 * 24 * 15,
    cookieCache: {
      enabled: isProduction,
      maxAge: 5 * 60,
    },
  },
} satisfies BetterAuthOptions;

const auth = betterAuth(betterAuthOptions);

Current vs. Expected behavior

I encountered a suspected bug: When the user.emailVerified field in the database is already verified (true), requesting the /send-verification-email endpoint again still sends a verification email to the already verified email account.

I'm not sure if this is a bug or intentional, and my current solution is to add a check with if (user.emailVerified) inside sendVerificationEmail and return early before actually sending the email.

What version of Better Auth are you using?

1.4.18

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 10 Pro",
    "release": "10.0.19045",
    "cpuCount": 12,
    "cpuModel": "AMD Ryzen 5 3600X 6-Core Processor             ",
    "totalMemory": "15.93 GB",
    "freeMemory": "4.91 GB"
  },
  "node": {
    "version": "v24.13.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.8.0"
  },
  "frameworks": null,
  "databases": null,
  "betterAuth": {
    "version": "Unknown",
    "config": null
  }
}

Which area(s) are affected? (Select all that apply)

Client

Auth config (if applicable)


Additional context

I am currently only reproducing it locally, and I am making requests to all the API endpoints exposed by better-auth through Postman, without using the authClient of better-auth.

Originally created by @shinexoh on GitHub (Jan 30, 2026). Originally assigned to: @bytaesu on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce ```typescript import { drizzleAdapter } from 'better-auth/adapters/drizzle'; import { betterAuth, type BetterAuthOptions } from 'better-auth/minimal'; const betterAuthOptions = { basePath: '/auth', appName: envConfig.APP_NAME, baseURL: envConfig.BETTER_AUTH_URL, secret: envConfig.BETTER_AUTH_SECRET, trustedOrigins: envConfig.TRUSTED_ORIGINS, plugins: [ admin({ defaultRole: 'user', adminRoles: ['admin'], }), openAPI(), ], database: drizzleAdapter(db, { provider: 'pg', usePlural: true, schema, }), secondaryStorage: { // ... }, emailAndPassword: { enabled: true, autoSignIn: true, requireEmailVerification: true, revokeSessionsOnPasswordReset: true, sendResetPassword: async ({ user, url }) => { void sendEmail({ to: user.email, subject: 'Reset your password', html: resetPasswordTemplate({ url }), }); }, password: { hash: hashPassword, verify: async (data) => verifyPassword(data.password, data.hash), }, }, emailVerification: { sendOnSignIn: false, sendOnSignUp: false, expiresIn: 60 * 60 * 12, autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url }) => { void sendEmail({ to: user.email, subject: 'Verify your email', html: verifyEmailTemplate({ url }), }); }, afterEmailVerification: async (user) => { // ... }, }, advanced: { cookiePrefix: envConfig.APP_NAME, database: { generateId: false, }, }, user: { deleteUser: { enabled: true, sendDeleteAccountVerification: async ({ user, url }) => { // ... }, }, }, session: { expiresIn: 60 * 60 * 24 * 15, cookieCache: { enabled: isProduction, maxAge: 5 * 60, }, }, } satisfies BetterAuthOptions; const auth = betterAuth(betterAuthOptions); ``` ### Current vs. Expected behavior I encountered a suspected bug: When the `user.emailVerified` field in the database is already verified (true), requesting the `/send-verification-email` endpoint again still sends a verification email to the already verified email account. I'm not sure if this is a bug or intentional, and my current solution is to add a check with `if (user.emailVerified)` inside `sendVerificationEmail` and return early before actually sending the email. ### What version of Better Auth are you using? 1.4.18 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 10 Pro", "release": "10.0.19045", "cpuCount": 12, "cpuModel": "AMD Ryzen 5 3600X 6-Core Processor ", "totalMemory": "15.93 GB", "freeMemory": "4.91 GB" }, "node": { "version": "v24.13.0", "env": "development" }, "packageManager": { "name": "npm", "version": "11.8.0" }, "frameworks": null, "databases": null, "betterAuth": { "version": "Unknown", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript ``` ### Additional context I am currently only reproducing it locally, and I am making requests to all the API endpoints exposed by `better-auth` through `Postman`, without using the `authClient` of `better-auth`.
GiteaMirror added the bug label 2026-03-13 10:20:36 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 30, 2026):

It seems you're experiencing an issue where the /send-verification-email endpoint sends a verification email even when the user.emailVerified field is set to true. This appears to be a recognized issue, as there is a bug report regarding unexpected email verification behaviors in similar contexts, specifically concerning the sending of verification emails to already verified addresses [1, 2, 6].

Your approach to add a check for if (user.emailVerified) inside the sendVerificationEmail function is a reasonable temporary solution. This will prevent the unnecessary sending of emails for users who have already verified their emails.

If you want more directed support, please consider tagging @bekacru or @ping__ for further assistance regarding this matter. What have you tried so far in adjusting the verification email logic?

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Jan 30, 2026): It seems you're experiencing an issue where the `/send-verification-email` endpoint sends a verification email even when the `user.emailVerified` field is set to `true`. This appears to be a recognized issue, as there is a bug report regarding unexpected email verification behaviors in similar contexts, specifically concerning the sending of verification emails to already verified addresses [1, 2, 6]. Your approach to add a check for `if (user.emailVerified)` inside the `sendVerificationEmail` function is a reasonable temporary solution. This will prevent the unnecessary sending of emails for users who have already verified their emails. If you want more directed support, please consider tagging @bekacru or @ping__ for further assistance regarding this matter. What have you tried so far in adjusting the verification email logic? _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

@dosubot[bot] commented on GitHub (Jan 30, 2026):

Hi @shinexoh! I'm Dosu and I’m helping the better-auth team.

This is intentional: when you call /send-verification-email without an authenticated session (like via Postman), Better Auth looks up the user by email and sends a verification email regardless of whether user.emailVerified is true—there’s no built-in check for that in this flow. The endpoint is designed for self-service, not for admins or other users to trigger verification emails for someone else. If you call the endpoint with a session, it does check emailVerified and will block the request if the email is already verified (code reference, PR #7215, issue #5621).

The recommended workaround is exactly what you’re doing: add a check for user.emailVerified in your custom sendVerificationEmail handler and return early if it’s true (example, discussion). There’s no config option to change this behavior for unauthenticated requests.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Jan 30, 2026): <!-- Greeting --> Hi @shinexoh! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is intentional: when you call `/send-verification-email` without an authenticated session (like via Postman), Better Auth looks up the user by email and sends a verification email regardless of whether `user.emailVerified` is true—there’s no built-in check for that in this flow. The endpoint is designed for self-service, not for admins or other users to trigger verification emails for someone else. If you call the endpoint with a session, it does check `emailVerified` and will block the request if the email is already verified ([code reference](https://github.com/better-auth/better-auth/blob/583f12fb7db38681ee882d219ce3895faa4a6976/packages/better-auth/src/api/routes/email-verification.ts#L47-L198), [PR #7215](https://github.com/better-auth/better-auth/pull/7215), [issue #5621](https://github.com/better-auth/better-auth/issues/5621)). The recommended workaround is exactly what you’re doing: add a check for `user.emailVerified` in your custom `sendVerificationEmail` handler and return early if it’s true ([example](https://github.com/better-auth/better-auth/issues/6644), [discussion](https://github.com/better-auth/better-auth/issues/3742)). There’s no config option to change this behavior for unauthenticated requests. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/e07359a7-e48d-43ef-a91f-e469cd0b17f9?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/e07359a7-e48d-43ef-a91f-e469cd0b17f9?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/e07359a7-e48d-43ef-a91f-e469cd0b17f9?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/e07359a7-e48d-43ef-a91f-e469cd0b17f9?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/e07359a7-e48d-43ef-a91f-e469cd0b17f9?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/e07359a7-e48d-43ef-a91f-e469cd0b17f9?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/e07359a7-e48d-43ef-a91f-e469cd0b17f9?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20intentional%3A%20when%20you%20call%20%60/send-verification-email%60%20without%20an%20authenticated%20session%20%28like%20via%20Postman%29%2C%20Better%20Auth%20looks%20up%20the%20user%20by%20email%20and%20sends%20a%20verification%20email%20regardless%20of%20whether%20%60user.emailVerified%60%20is%20true%E2%80%94there%E2%80%99s%20no%20built-in%20check%20for%20that%20in%20this%20flow.%20The%20endpoint%20is%20designed%20for%20self-service%2C%20not%20for%20admins%20or%20other%20users%20to%20trigger%20verification%20emails%20for%20someone%20else.%20If%20you%20call%20the%20endpoint%20with%20a%20session%2C%20it%20does%20check%20%60emailVerified%60%20and%20will%20block%20the%20request%20if%20the%20email%20is%20already%20verified%C2%A0%28%5Bcode%20reference%5D%28https%3A//github.com/better-auth/better-auth/blob/583f12fb7db38681ee882d219ce3895faa4a6976/packages/better-auth/src/api/routes/email-verification.ts%23L47-L198%29%2C%20%5BPR%20%237215%5D%28https%3A//github.com/better-auth/better-auth/pull/7215%29%2C%20%5Bissue%20%235621%5D%28https%3A//github.com/better-auth/better-auth/issues/5621%29%29.%0A%0AThe%20recommended%20workaround%20is%20exactly%20what%20you%E2%80%99re%20doing%3A%20add%20a%20check%20for%20%60user.emailVerified%60%20in%20your%20custom%20%60sendVerificationEmail%60%20handler%20and%20return%20early%20if%20it%E2%80%99s%20true%C2%A0%28%5Bexample%5D%28https%3A//github.com/better-auth/better-auth/issues/6644%29%2C%20%5Bdiscussion%5D%28https%3A//github.com/better-auth/better-auth/issues/3742%29%29.%20There%E2%80%99s%20no%20config%20option%20to%20change%20this%20behavior%20for%20unauthenticated%20requests.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/7707)
Author
Owner

@shinexoh commented on GitHub (Jan 30, 2026):

I didn't understand. What you're saying is that if I make a request to the /send-verification-email endpoint in Postman without including the user's session, the emailVerified field won't be checked before sending the email, and the verification email will always be sent to the target email? But if the session is included, it will check if emailVerified is true and then not send the email?

@shinexoh commented on GitHub (Jan 30, 2026): I didn't understand. What you're saying is that if I make a request to the `/send-verification-email` endpoint in Postman without including the user's `session`, the `emailVerified` field won't be checked before sending the email, and the verification email will always be sent to the target email? But if the `session` is included, it will check if `emailVerified` is `true` and then not send the email?
Author
Owner

@dosubot[bot] commented on GitHub (Jan 30, 2026):

Yes, that's correct. If you call /send-verification-email without a session (for example, from Postman without cookies or tokens), Better Auth does not check if emailVerified is true—it will always send a verification email to the target address, even if that email is already verified. If you call the endpoint with a valid session (the user is logged in), it checks if emailVerified is true for that user and will block the request with an EMAIL_ALREADY_VERIFIED error if so, so no email is sent in that case. This is intentional and matches the current code and design of the endpoint see code reference PR #7215 issue #5621.

If you want to prevent emails from being sent to already verified users in the unauthenticated flow, you’ll need to add a check for user.emailVerified in your custom sendVerificationEmail handler.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Jan 30, 2026): <!-- Answer --> Yes, that's correct. If you call /send-verification-email without a session (for example, from Postman without cookies or tokens), Better Auth does not check if emailVerified is true—it will always send a verification email to the target address, even if that email is already verified. If you call the endpoint with a valid session (the user is logged in), it checks if emailVerified is true for that user and will block the request with an EMAIL_ALREADY_VERIFIED error if so, so no email is sent in that case. This is intentional and matches the current code and design of the endpoint [see code reference](https://github.com/better-auth/better-auth/blob/583f12fb7db38681ee882d219ce3895faa4a6976/packages/better-auth/src/api/routes/email-verification.ts#L47-L203) [PR #7215](https://github.com/better-auth/better-auth/pull/7215) [issue #5621](https://github.com/better-auth/better-auth/issues/5621). If you want to prevent emails from being sent to already verified users in the unauthenticated flow, you’ll need to add a check for user.emailVerified in your custom sendVerificationEmail handler. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/209e426a-5f62-45ef-980a-3dfbde3c3443?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/209e426a-5f62-45ef-980a-3dfbde3c3443?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/209e426a-5f62-45ef-980a-3dfbde3c3443?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/209e426a-5f62-45ef-980a-3dfbde3c3443?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/209e426a-5f62-45ef-980a-3dfbde3c3443?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/209e426a-5f62-45ef-980a-3dfbde3c3443?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/209e426a-5f62-45ef-980a-3dfbde3c3443?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Yes%2C%20that%27s%20correct.%20If%20you%20call%20/send-verification-email%20without%20a%20session%20%28for%20example%2C%20from%20Postman%20without%20cookies%20or%20tokens%29%2C%20Better%20Auth%20does%20not%20check%20if%20emailVerified%20is%20true%E2%80%94it%20will%20always%20send%20a%20verification%20email%20to%20the%20target%20address%2C%20even%20if%20that%20email%20is%20already%20verified.%20If%20you%20call%20the%20endpoint%20with%20a%20valid%20session%20%28the%20user%20is%20logged%20in%29%2C%20it%20checks%20if%20emailVerified%20is%20true%20for%20that%20user%20and%20will%20block%20the%20request%20with%20an%20EMAIL_ALREADY_VERIFIED%20error%20if%20so%2C%20so%20no%20email%20is%20sent%20in%20that%20case.%20This%20is%20intentional%20and%20matches%20the%20current%20code%20and%20design%20of%20the%20endpoint%C2%A0%5Bsee%20code%20reference%5D%28https%3A//github.com/better-auth/better-auth/blob/583f12fb7db38681ee882d219ce3895faa4a6976/packages/better-auth/src/api/routes/email-verification.ts%23L47-L203%29%C2%A0%5BPR%20%237215%5D%28https%3A//github.com/better-auth/better-auth/pull/7215%29%C2%A0%5Bissue%20%235621%5D%28https%3A//github.com/better-auth/better-auth/issues/5621%29.%0A%0AIf%20you%20want%20to%20prevent%20emails%20from%20being%20sent%20to%20already%20verified%20users%20in%20the%20unauthenticated%20flow%2C%20you%E2%80%99ll%20need%20to%20add%20a%20check%20for%20user.emailVerified%20in%20your%20custom%20sendVerificationEmail%20handler.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/7707)
Author
Owner

@shinexoh commented on GitHub (Jan 30, 2026):

Why design it this way? Won't this lead to email abuse? @himself65

@shinexoh commented on GitHub (Jan 30, 2026): Why design it this way? Won't this lead to email abuse? @himself65
Author
Owner

@dosubot[bot] commented on GitHub (Jan 30, 2026):

This design is intentional: the /send-verification-email endpoint is meant for self-service, so users can trigger verification emails for themselves even if they're not logged in (for example, if they want to verify from a different device or browser). When called without a session, it sends the email regardless of the emailVerified status, because it can't reliably know who is making the request—this supports passwordless and recovery flows. When called with a session, it checks that the session user matches the email and blocks the request if already verified, to prevent abuse by logged-in users trying to trigger emails for others (PR #7215, issue #5621).

However, this does mean that, unless you add your own checks or rate limiting, someone could spam verification emails to any address by repeatedly calling the endpoint unauthenticated. The maintainers are aware of this trade-off between usability and security, and in other flows (like email change or OTP), they sometimes enforce session checks or add abuse mitigations (PR #7252, PR #5050). For /send-verification-email, the expectation is that developers add their own checks in the sendVerificationEmail handler or implement rate limiting at the API gateway or server level if stricter controls are needed.

If you want to avoid this risk, you can add a check for user.emailVerified in your handler, or implement rate limiting to prevent abuse. If you think this should be built-in, it might be worth proposing as a feature request.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Jan 30, 2026): <!-- Answer --> This design is intentional: the /send-verification-email endpoint is meant for self-service, so users can trigger verification emails for themselves even if they're not logged in (for example, if they want to verify from a different device or browser). When called without a session, it sends the email regardless of the emailVerified status, because it can't reliably know who is making the request—this supports passwordless and recovery flows. When called with a session, it checks that the session user matches the email and blocks the request if already verified, to prevent abuse by logged-in users trying to trigger emails for others ([PR #7215](https://github.com/better-auth/better-auth/pull/7215), [issue #5621](https://github.com/better-auth/better-auth/issues/5621)). However, this does mean that, unless you add your own checks or rate limiting, someone could spam verification emails to any address by repeatedly calling the endpoint unauthenticated. The maintainers are aware of this trade-off between usability and security, and in other flows (like email change or OTP), they sometimes enforce session checks or add abuse mitigations ([PR #7252](https://github.com/better-auth/better-auth/pull/7252), [PR #5050](https://github.com/better-auth/better-auth/pull/5050)). For /send-verification-email, the expectation is that developers add their own checks in the sendVerificationEmail handler or implement rate limiting at the API gateway or server level if stricter controls are needed. If you want to avoid this risk, you can add a check for user.emailVerified in your handler, or implement rate limiting to prevent abuse. If you think this should be built-in, it might be worth proposing as a feature request. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/eb75dc6a-589d-46fe-b6cb-5b5a62bc73fc?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/eb75dc6a-589d-46fe-b6cb-5b5a62bc73fc?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/eb75dc6a-589d-46fe-b6cb-5b5a62bc73fc?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/eb75dc6a-589d-46fe-b6cb-5b5a62bc73fc?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/eb75dc6a-589d-46fe-b6cb-5b5a62bc73fc?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/eb75dc6a-589d-46fe-b6cb-5b5a62bc73fc?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/eb75dc6a-589d-46fe-b6cb-5b5a62bc73fc?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20design%20is%20intentional%3A%20the%20/send-verification-email%20endpoint%20is%20meant%20for%20self-service%2C%20so%20users%20can%20trigger%20verification%20emails%20for%20themselves%20even%20if%20they%27re%20not%20logged%20in%20%28for%20example%2C%20if%20they%20want%20to%20verify%20from%20a%20different%20device%20or%20browser%29.%20When%20called%20without%20a%20session%2C%20it%20sends%20the%20email%20regardless%20of%20the%20emailVerified%20status%2C%20because%20it%20can%27t%20reliably%20know%20who%20is%20making%20the%20request%E2%80%94this%20supports%20passwordless%20and%20recovery%20flows.%20When%20called%20with%20a%20session%2C%20it%20checks%20that%20the%20session%20user%20matches%20the%20email%20and%20blocks%20the%20request%20if%20already%20verified%2C%20to%20prevent%20abuse%20by%20logged-in%20users%20trying%20to%20trigger%20emails%20for%20others%C2%A0%28%5BPR%20%237215%5D%28https%3A//github.com/better-auth/better-auth/pull/7215%29%2C%20%5Bissue%20%235621%5D%28https%3A//github.com/better-auth/better-auth/issues/5621%29%29.%0A%0AHowever%2C%20this%20does%20mean%20that%2C%20unless%20you%20add%20your%20own%20checks%20or%20rate%20limiting%2C%20someone%20could%20spam%20verification%20emails%20to%20any%20address%20by%20repeatedly%20calling%20the%20endpoint%20unauthenticated.%20The%20maintainers%20are%20aware%20of%20this%20trade-off%20between%20usability%20and%20security%2C%20and%20in%20other%20flows%20%28like%20email%20change%20or%20OTP%29%2C%20they%20sometimes%20enforce%20session%20checks%20or%20add%20abuse%20mitigations%C2%A0%28%5BPR%20%237252%5D%28https%3A//github.com/better-auth/better-auth/pull/7252%29%2C%20%5BPR%20%235050%5D%28https%3A//github.com/better-auth/better-auth/pull/5050%29%29.%20For%20/send-verification-email%2C%20the%20expectation%20is%20that%20developers%20add%20their%20own%20checks%20in%20the%20sendVerificationEmail%20handler%20or%20implement%20rate%20limiting%20at%20the%20API%20gateway%20or%20server%20level%20if%20stricter%20controls%20are%20needed.%0A%0AIf%20you%20want%20to%20avoid%20this%20risk%2C%20you%20can%20add%20a%20check%20for%20user.emailVerified%20in%20your%20handler%2C%20or%20implement%20rate%20limiting%20to%20prevent%20abuse.%20If%20you%20think%20this%20should%20be%20built-in%2C%20it%20might%20be%20worth%20proposing%20as%20a%20feature%20request.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/7707)
Author
Owner

@bytaesu commented on GitHub (Jan 30, 2026):

Hi @shinexoh, I'm checking this

@bytaesu commented on GitHub (Jan 30, 2026): Hi @shinexoh, I'm checking this
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2794