---
title: "Test Better Auth verification, magic link and OTP emails · Proxy Mail QA"
description: "Test Better Auth's verification, reset, magic-link and email OTP emails, sent through your own provider, and their 5-minute expiry by default."
url: https://proxymail.qa/auth/better-auth
---

1. [Home](https://proxymail.qa/)
2. [Auth providers](https://proxymail.qa/auth)

# Test Better Auth emails

Better Auth doesn't send email itself: you write the functions that send its verification, password reset, magic link and email OTP messages through your own provider. That makes testing the email essential, since a typo in your sending code or a provider in sandbox mode means nothing arrives. Sign up with a fresh Proxy Mail QA address and the code or link shows up on its row.

Updated October 17, 2026

Defaults below are from Better Auth’s documentation on 17 October 2026\. Check it for current details.

## What you send, and when

| Email                | Your function                           | Notes                                                                                       |
| -------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------- |
| Address verification | emailVerification.sendVerificationEmail | Sent at sign-up with sendOnSignUp: true                                                     |
| Password reset       | emailAndPassword.sendResetPassword      | A link to set a new password                                                                |
| Magic link           | sendMagicLink (magic link plugin)       | Expires after 300 seconds by default; works once                                            |
| Email OTP            | sendVerificationOTP (email OTP plugin)  | 6 digits, 300 seconds, 3 attempts by default; for sign-in, verification or a password reset |

Better Auth’s docs suggest not awaiting the send, to avoid timing attacks. On serverless platforms that means using `waitUntil` or similar, or the function can end before the email goes.

## Test it by hand

1. Create an address in Proxy Mail QA, with a persona and password if your form asks.
2. Sign up in your app with it.
3. The link or code appears on the address’s row within seconds, with a countdown when the email says how long it lasts.

Try the edges too: sign in before verifying (refused with `requireEmailVerification`), open a magic link twice (the second time fails), and wait past five minutes.

## Automate it

otp.spec.ts

```ts
import { test, expect } from 'proxymail-qa/playwright';

test('email OTP sign-in works', async ({ page, qa }) => {
  const { address } = await qa.createAddress();
  const requested = new Date();
  await page.goto('/sign-in');
  await page.getByLabel('Email').fill(address);
  await page.getByRole('button', { name: 'Send code' }).click();

  const { value } = await qa.waitForCode(address, { since: requested });
  await page.getByLabel('Code').fill(value);
  await expect(page).toHaveURL(/dashboard/);
});

```

For links, use `qa.waitForLink(address, { type: 'verify', since })` or `type: 'magic_signin'` and open them. More in [Test sign-up emails in Playwright](https://proxymail.qa/solve/playwright-email-tests).

## Try it on your next sign-up test

Free plan, no credit card. Create an address and watch the code or link arrive.

[Create a free account](https://app.proxymail.qa/?mode=signup)

## Questions

### How long do Better Auth magic links and codes last?

Five minutes by default: the magic link plugin's expiresIn and the email OTP plugin's expiresIn are both 300 seconds. A magic link works once. An email OTP allows 3 wrong attempts before a new one is needed.

### Why didn't the verification email arrive?

Check that emailVerification.sendOnSignUp is on and that your sendVerificationEmail function calls your provider. Then check the provider isn't in sandbox mode, where it only sends to verified addresses.

### Can users sign in before verifying?

Not when emailAndPassword.requireEmailVerification is on: sign-in fails with a 403 until the address is verified. Test both: an unverified sign-in is refused, and it works once the link is opened.

## Related guides

- [Supabase AuthConfirmation, magic-link, code and reset emails, and why the default sender won't email your test addresses.](https://proxymail.qa/auth/supabase)
- [ClerkVerification codes, email links and resets, when test-mode addresses aren't enough, and the development email cap.](https://proxymail.qa/auth/clerk)
- [Auth0Verification links, passwordless codes and resets, and the built-in email provider's limits.](https://proxymail.qa/auth/auth0)
- [Firebase AuthenticationVerification, reset and email-link sign-in emails on the web, and the daily sending limits.](https://proxymail.qa/auth/firebase)
- [Auth.js (NextAuth)Magic-link sign-in through your own email provider, its expiry, and what stops the email arriving.](https://proxymail.qa/auth/authjs)

[See every email testing problem we solve](https://proxymail.qa/solve)

Better Auth is a trademark of its owner. Proxy Mail QA is independent and isn't affiliated with or endorsed by them.
