Deny registration attempts from known disposable or temporary email providers before the user account is created.
When to use it
Section titled “When to use it”This recipe suits any product where account quality matters — B2B SaaS trials especially. Disposable email addresses are the primary mechanism for abusing free tiers: a user exhausts a trial, creates a new inbox at mailinator or tempmail, and starts again. Blocking at the Pre-Create stage stops the account from existing at all, which means no leftover data to clean up and no false positives in your user metrics.
The check runs entirely inside the platform, with no external API calls. It is instant and has no per-check cost.
What you will build
Section titled “What you will build”A custom action attached to the Registration flow's Pre-Create stage. The action reads event.user.email, lowercases the domain, checks it against a list of known disposable providers, and calls api.deny if there is a match. Because it sits in the Pre-Create stage, the identity is never written — the flow halts cleanly.
The complete configuration is:
- A custom action named
block-disposable-emails, trigger Registration. - A Run Custom Action block added to the Pre-Create stage of the Registration flow.
- The Run Custom Action block configured to run
block-disposable-emails.
Configure it
Section titled “Configure it”Step 1 — Create the custom action
Section titled “Step 1 — Create the custom action”Open Custom Actions in the left navigation and click + New Action.
Set:
- Name:
block-disposable-emails - Trigger: Registration
Leave the other settings at their defaults and click Save. The editor opens.
Step 2 — Paste the code
Section titled “Step 2 — Paste the code”Replace the default function body with the code in the Code section below. Click Save.
/screenshots/tenant-admin/flows/recipes/block-disposable-emails-action-editor.png Step 3 — Enable the action
Section titled “Step 3 — Enable the action”Toggle the action to Enabled in the action detail header. A disabled action is ignored even when the block calls it.
Step 4 — Add the block to the Registration flow
Section titled “Step 4 — Add the block to the Registration flow”Navigate to Flows, click Registration, then click Edit.
In the flow editor, expand the Pre-Create stage. Drag a Run Custom Action block from the block palette into the Pre-Create stage.
In the block's configuration panel, select block-disposable-emails from the Action dropdown. Click Save.
/screenshots/tenant-admin/flows/recipes/block-disposable-emails-flow-editor.png Step 5 — Publish the flow
Section titled “Step 5 — Publish the flow”Click Publish in the flow editor toolbar. The change is live immediately for new registrations.
The code
Section titled “The code”async function blockDisposableEmails(event, api) { // Extend this list as new disposable providers appear. // For a production deployment, consider replacing the inline array // with an api.fetch call to a CDN-hosted list your team controls. const disposableDomains = [ 'mailinator.com', 'tempmail.com', 'guerrillamail.com', 'throwam.com', 'sharklasers.com', 'yopmail.com', 'trashmail.com', 'dispostable.com', 'fakeinbox.com', 'maildrop.cc', 'getairmail.com', 'spamgourmet.com', '10minutemail.com', 'tempr.email', 'discard.email', ];
const email = event.user.email ?? ''; const domain = email.split('@')[1]?.toLowerCase() ?? '';
if (!domain) { // Malformed email — deny before the identity is written. api.log('warn', 'Registration blocked: no domain found in email address'); api.deny('malformed-email-address'); return; }
if (disposableDomains.includes(domain)) { // Write the blocked domain to the audit log so you can track // which providers are being used against your tenant. // Do NOT surface the reason string to the user — it tells attackers // which domains are blocked and which are not. api.log('warn', `Registration blocked: disposable domain ${domain}`); api.deny('disposable-email-blocked'); return; }
// Optional: log allowed signups during rollout so you can audit // the first few days and confirm no legitimate domains are in the list. api.log('info', `Registration allowed: ${domain}`);}Test it
Section titled “Test it”Open the action in Custom Actions, click Test, and select the New registration preset.
In the Event JSON editor, find the user.email field and change the value to someone@mailinator.com. Click Run.
In the API calls tab of the result, you should see:
api.logcalled with'warn'and a message containingmailinator.com.api.denycalled with'disposable-email-blocked'.
No api.user.setAppMetadata or api.session.setCustomClaim calls should appear — the action returned early after the deny.
Now change the email to a normal address (test@example.com) and run again. This time you should see only the api.log info entry and no api.deny call.
Verify on a live flow
Section titled “Verify on a live flow”Navigate to your tenant's registration URL — https://<tenant>-<org>.intelliauth.local/register or your production equivalent.
Attempt to register with test+disposable@mailinator.com. The registration form should show your tenant's standard error message ("We couldn't complete your registration" or equivalent). The specific reason disposable-email-blocked is never shown to the user.
Navigate to Flows → Registration → Recent Runs in the admin console. The most recent run should show status Denied with the action name and the reason disposable-email-blocked visible in the run detail.
Cautions
Section titled “Cautions”The blocklist is hard-coded. The list above covers common providers but not the full universe of disposable email services, which numbers in the hundreds. For serious abuse protection, replace the inline array with an api.fetch call that downloads a community-maintained list from a URL on your tenant's fetch allowlist. Update the list at least monthly.
Never surface the deny reason to the user. The api.deny reason string goes to your audit log, not to the registration form. If you customise your error templates, use a generic message. A specific message like "mailinator.com addresses are not allowed" tells abusers which domain to try next.
Pre-Create is the right stage. If you move this block to Post-Create, the identity has already been written by the time your action runs, and the deny leaves an orphaned identity record in the platform. Pre-Create is the only safe location for this check.