If your app already uses Better Auth, you do not need to build a separate email-check endpoint just to screen signups. The MailRambo plugin adds a server-side check before the email/password signup handler creates a user or sends a confirmation email.
This guide covers better-auth-mailrambo@0.1.0, tested with Better Auth 1.7.7 on Node.js 22.23.3 and 26.7.0. The public source and tests are MIT licensed. This is a MailRambo integration, not a built-in or endorsed Better Auth plugin.
What it checks - and what it does not
The plugin calls MailRambo's free mode=fast API to screen syntax, common domain typos, disposable providers and whether the domain can receive email. It does not confirm mailbox existence, email ownership or identity. A passed check is permission to continue under your app's existing rules, not proof of a genuine user.
Version 0.1.0 covers /sign-up/email only, through both Better Auth's HTTP handler and auth.api.signUpEmail. It does not screen OAuth/social signup, OTP, magic links, email changes, custom signup endpoints, raw endpoint-function calls or manual database writes. Keep email confirmation, rate limits and any CAPTCHA or device controls you already use.
1. Check compatibility and install
The package has an exact peer requirement of Better Auth 1.7.7 and requires Node.js 22 or later. Check your application's installed version first:
npm ls better-auth
node --version
Do not blindly upgrade an existing application's auth framework just to match this guide. If it uses another version, review and test that upgrade separately; this plugin does not currently certify a broader version range. Do not force installation past a peer-dependency conflict.
For a compatible app, install the plugin:
npm install better-auth-mailrambo@0.1.0
The plugin brings its MailRambo SDK dependency with it. No client-side plugin, new database tables or migrations are required by this integration.
2. Create a dedicated server-side key
Create a MailRambo account, then open API Keys. Name a dedicated key after this integration so you can revoke it without affecting unrelated projects. Copy it when shown; the full key is displayed only once.
Store it in your server environment:
MAILRAMBO_API_KEY=your_mailrambo_api_key
Do not commit the key or prefix the variable with NEXT_PUBLIC_, VITE_ or anything that exposes it to the browser. On Vercel, set it in the project's environment settings for the environments that run your auth backend.
Both live and test keys run real fast checks. Test keys simulate full mailbox checks, but the plugin uses fast mode only. Do not expect canned disposable@ or deliverable@ full-check fixtures when exercising this plugin.
3. Add it without replacing your auth configuration
Add the plugin to your existing server-side configuration and preserve existing plugins and options:
import { betterAuth } from "better-auth";
import { mailramboEmailCheck } from "better-auth-mailrambo";
import { existingAuthOptions } from "./auth-options";
export const auth = betterAuth({
...existingAuthOptions,
plugins: [
...(existingAuthOptions.plugins ?? []),
mailramboEmailCheck(),
],
});
./auth-options represents your own application's existing options, not a file shipped by the plugin. Keep your database, secret, route handler, email/password settings and verification-email callback. If you already set requireEmailVerification, leave it enabled. The plugin does not enable or disable email confirmation for you.
The only optional settings are the API key, remote timeout and a custom server-side fetch:
mailramboEmailCheck({
apiKey: process.env.MAILRAMBO_API_KEY,
timeout: 2000,
// fetch: yourServerFetch,
});
The default remote timeout is 2,000 milliseconds, with zero automatic retries. It is not a guarantee for total signup latency. A custom fetch must respect the supplied AbortSignal, including response-body cancellation.
4. Understand the signup decisions
| Fast-mode result | Plugin behavior |
|---|---|
deliverable: false, invalid_syntax |
Reject and ask for a valid address |
deliverable: false, possible_typo |
Reject and ask the user to check spelling |
deliverable: false, disposable |
Reject and ask for a permanent address |
deliverable: false, no_mx |
Reject and ask for a mail-capable domain |
deliverable: null, fast_check_passed |
Continue; the mailbox is still unverified |
| API/network error, timeout or unusable response | Continue under existing Better Auth rules |
These are fixed policies in version 0.1.0, not configurable lists of allowed reasons. Role-account and free-provider flags alone do not cause rejection. The plugin does not silently apply typo suggestions, strip plus tags, remove dots or rewrite the submitted address.
Our generic signup UX guide discusses letting a user override a typo suggestion in a custom form. That is a different policy: this plugin rejects possible_typo. If you need user overrides or other custom decisions, do not assume 0.1.0 exposes those options.
5. Display errors and preserve email confirmation
HTTP signup rejects a known screening failure with status 400, code: "MAILRAMBO_EMAIL_REJECTED" and a static user-facing message. Your existing Better Auth client can display the returned error through its normal signup error UI. The plugin does not add a separate client plugin.
For direct server calls, Better Auth 1.7.7 throws the before-hook APIError even when asResponse: true is requested. Handle the plugin error without swallowing unrelated auth errors:
import { APIError } from "better-auth/api";
try {
await auth.api.signUpEmail({ body: signupData });
} catch (error) {
if (error instanceof APIError && error.body?.code === "MAILRAMBO_EMAIL_REJECTED") {
// Return error.body.message using your application's error handling.
} else {
throw error;
}
}
signupData is your signup request with the usual name, email and password fields. A passed screen does not mark the new user as email-verified. Confirmation must still use your existing verification flow.
Why signup fails open
Signup continues if MailRambo is unavailable, times out, returns an API error or produces an unusable result. That includes runtime 401 responses for an invalid/revoked key, 429 rate limits and server errors. This is an availability-first choice, not a promise of continuous abuse protection.
There is an important operational consequence: an invalid or revoked key can leave signup working while screening is skipped. Check your deployment configuration and monitor the integration separately. Version 0.1.0 does not expose an error-reporting callback or automatically alert you.
Missing or empty credentials, an invalid timeout or an invalid fetch option instead throw a startup configuration error. They are not remote service failures; fix them before serving traffic.
Cost, privacy and testing
There is no separate plugin fee. Fast checks consume no verification credits and can be used with an account on any API-enabled plan, including Free. Authentication and API rate limits still apply. A full mailbox check is a separate API action, normally charged according to MailRambo pricing; it is not performed by this plugin.
Screening sends the signup email address to MailRambo over HTTPS. Review that data flow for your application's privacy notice and policies. The plugin does not log email addresses or credentials, but Better Auth, your backend and your infrastructure may have their own logging policies.
Before production, test in staging:
- A normal address continues signup and remains unverified until your normal confirmation completes.
- A known screening failure creates no user and sends no confirmation email.
- A mocked outage or timeout continues ordinary signup and email confirmation.
- Login and unsupported auth flows do not unexpectedly trigger screening.
The public package's tests cover these behaviors using mocked requests and Better Auth's memory adapter. Do not run that memory adapter or its fixture secrets in production. Use the disposable checker to inspect an address manually, and open a plugin issue for reproducible integration bugs.
The plugin reduces specific signup-email problems; it does not prevent every bot, multi-account or free-trial-abuse case. Keep layered abuse controls and email confirmation.