All posts

How to Verify Emails in Bubble.io With the API Connector

··11 min read

To verify emails in Bubble.io, add your verification API to the API Connector with Private key in header, create a POST call set to Use as: Action, and tick Include errors in response and allow workflow actions to continue. In your sign-up workflow, run the verify call first, then Sign the user up only when the result's status is not invalid. Show the reason when it is. For users you already have, a backend workflow scheduled on a list with a 1-second interval verifies them under the API's rate limit.

This guide sets that up step by step with SimpleVerifier's API. The same steps work with any verification API that takes an email and returns a status.

What you will build

Three pieces:

  1. An API Connector call named Verify email, with the key stored privately.
  2. A sign-up workflow that checks the address before creating the user, and tells the person what is wrong when it fails.
  3. A backend workflow that verifies existing users in batches and saves the result on each User.

Verification sits between the form and the account. Our guide to real-time verification on signup forms explains the timing trade-offs. This guide covers Bubble.

Step 1: Add the API with a private key

Install the API Connector plugin from the Plugins tab if your app doesn't have it. Then Add another API and name it SimpleVerifier.

Set the authentication at the collection level. Bubble's API Connector authentication guide describes Private key in header with three fields:

Field Value
Authentication Private key in header
Key name Authorization
Private key Bearer sv_live_... (your key, with "Bearer" and a space first)
Development key value Optional. A second key for your development version

Bubble's guide says that once configured, "the API Connector adds the header to every call in the collection automatically." It also says to include a prefix such as Bearer before the key, separated by a space.

On SimpleVerifier, keys start with sv_live_ and are shown once. The API docs explain how to create one. API access comes with a subscription. Pay-as-you-go packs cover CSV uploads only.

Why the key is safe here

Bubble's API Connector overview says calls are routed through Bubble's server by default, which keeps credentials off the user's device. Its API Connector security page adds the rules that matter:

  • Keys should never be stored where they can show up in your app's source code. Bubble names option sets, workflows, custom states, URL parameters and data type field defaults.
  • Initialization default values are visible in the app's code. Don't put sensitive values there, and clear them after initializing.
  • If a key ends up somewhere it shouldn't, disable it and create a new one.

Calling a verification API from the browser would expose the key. Anyone who can read it can use your plan. The API Connector avoids that.

Step 2: Create the Verify email call

Add a call under the SimpleVerifier API. Bubble's guide to adding calls documents each setting:

Setting Value
Name Verify email
Use as Action
Data type JSON
Method POST
URL https://simpleverifier.com/api/v1/verify
Body type JSON
Body { "email": "<email>" }
Include errors in response and allow workflow actions to continue Ticked

Typing <email> in the body creates a parameter called email. Leave its Private box unticked, because your workflows need to fill it with each address. The address is not a secret. The key is, and it already lives in the private header.

Action, not Data

Bubble's docs say a Data call populates elements and appears under "Get data from an external API". An Action call runs from a workflow. Use Action. You want exactly one call, at one step, when someone presses Sign up. Not one every time an element loads.

Why tick "Include errors in response"

Without it, an error from the API stops the workflow. With it, Bubble's docs say you get an error object with four fields: status code, status message, body and has returned error. The workflow carries on.

That turns an API problem into a non-event for your users. If the call fails, the status field is empty, and the sign-up condition in Step 4 still passes. Bubble's docs say to re-initialize the call if you change this option after initializing.

Step 3: Initialize the call

Bubble's docs say initialization sends a real request, then reads the response so you can use its fields in the editor. Enter an address you own as the test value for email and click Initialize call.

The response looks like this:

{
  "email": "jane@company.com",
  "status": "valid",
  "reason": "Mailbox exists",
  "mailbox_checked": true
}

Save it. Bubble now offers status, reason, email and mailbox_checked wherever you use the call's result. Then clear the test value, as Bubble's security page advises for default values.

What the fields mean

status Meaning Possible reason values
valid The mail server confirmed the mailbox exists Mailbox exists
risky It may work, but delivery isn't confirmed Accepts all addresses, Role-based address, Provider hides mailbox status, Server would not confirm, Mailbox check unavailable
invalid Don't send. It will bounce or it's a throwaway Invalid format, No mail server, Disposable address, Mailbox not found

Only invalid should stop a sign-up. risky usually means a catch-all domain, a shared inbox or a provider that hides mailbox status. Plenty of real customers sit behind those. Our guide to accept-all vs unknown results covers each reason.

Step 4: Check the address before Sign the user up

Add three fields to the User data type first, so you keep the result:

Field Type
email_status text
email_reason text
email_checked_at date

Add a custom state on the page, email_error (text), and a text element that shows it under the email input.

Now open the Sign up button's workflow and build these steps:

Step Action Settings Only when
1 Plugins > SimpleVerifier - Verify email email = Input Email's value Always
2 Set state of the page email_error = Result of step 1's reason Result of step 1's status is "invalid"
3 Terminate this workflow Result of step 1's status is "invalid"
4 Sign the user up Email = Input Email's value, Password = Input Password's value
5 Make changes to Current User email_status = Result of step 1's status, email_reason = Result of step 1's reason, email_checked_at = Current date/time

Step 3 stops the workflow on an invalid address, so Sign the user up never runs. Every other case, including an API error with an empty status, reaches Step 4.

Friendlier messages

The raw reason, such as "Mailbox not found", is clear enough for most apps. For softer wording, create an option set called Email reasons with an attribute message, and map each invalid reason:

Reason Message to show
Invalid format That email address doesn't look right. Please check it.
No mail server That email domain can't receive mail. Please check the spelling.
Disposable address Please sign up with a permanent email address.
Mailbox not found That mailbox doesn't exist. Please check the address.

Option sets are fine for messages. They are only a problem for secrets.

Show that something is happening

A live mailbox check talks to the recipient's mail server. Most answer within a few seconds, and some are slower. Our API docs recommend allowing about 30 seconds. Disable the button and show a loading indicator while Step 1 runs, so nobody clicks twice.

Worked example: three sign-ups

Three people press Sign up. The outcomes are illustrative, not measured.

  1. jane@gmial.com. Step 1 returns invalid, "No mail server". Step 2 shows "That email domain can't receive mail. Please check the spelling." Step 3 ends the workflow. Jane fixes the typo and signs up. Our guide to catching typos at signup shows how to suggest the fix directly.
  2. info@agency.example. Step 1 returns risky, "Role-based address". The account is created, and the User record shows the reason. Sales can decide whether to ask for a personal address later.
  3. sam@company.example during an API outage. Step 1 returns an error object and an empty status. Steps 2 and 3 are skipped. Sam signs up normally with an empty email_status, which the backend workflow below will fill in.

Step 5: Verify existing users with a backend workflow

Sign-up checks protect new users only. For the ones you have, use a backend workflow. Bubble's docs say API workflows are edited in the Backend workflows section of the editor. If you can't see it, enable backend workflows in your app's API settings first.

The workflow that checks one user

Create an API workflow named verify-user with one parameter, user, of type User:

Step Action Settings Only when
1 Plugins > SimpleVerifier - Verify email email = user's email Always
2 Make changes to a thing Thing = user; email_status = Result of step 1's status; email_reason = Result of step 1's reason; email_checked_at = Current date/time Result of step 1's status is not empty

The condition on Step 2 matters. A rate-limit or service error leaves the status empty, so the user stays unchecked and gets picked up on the next run.

Scheduling it on a list, under the rate limit

On an admin page, add a button whose workflow uses Schedule API workflow on a list:

Setting Value
Type of things User
List to run on Do a search for Users, constraint email_status is empty
API workflow verify-user
Scheduled date Current date/time
Interval 1
user This User

Bubble's scheduling guide explains the interval. It is the gap between scheduled workflows. Bubble says an interval can help when an external API has a strict rate limit. It also says the action supports up to 100,000 workflows, and that the scheduled workflows run in parallel rather than one after another.

SimpleVerifier allows 120 calls a minute per key, and returns HTTP 429 above that. Here is what each interval works out to:

Interval (seconds) Calls per minute (approx.) Room left for live sign-ups
0.5 120 None
1 60 About 60 a minute
2 30 About 90 a minute

Pick 1 second if your sign-up page shares the same key. The limit is per key, not per workflow. Our guide to handling API rate limits covers what 429 responses mean and how to back off.

Leaving the interval blank is not a good fit here. Bubble says a blank interval leaves only "a slight gap", and the guide warns that an interval of 0 can block other scheduled workflows until the whole batch is done.

How long it takes

At a 1-second interval, 3,000 users take about 50 minutes and 10,000 take close to three hours. Each scheduled workflow and API call also uses workload units on your Bubble plan. Check Bubble's pricing before running a large batch.

When to upload a CSV instead

Bubble backend workflows suit hundreds or a few thousand users. For a large user base, export the User table to CSV, upload it for bulk verification, and import the results back by unique ID or email. It avoids thousands of scheduled workflows and the workload units they use. Our guide on removing invalid emails from a CSV walks through the file side.

Common problems

Symptom Likely cause Fix
Every call returns 401 Private key missing "Bearer " Re-enter it as Bearer sv_live_...
Every call returns 402 Subscription not active Check the plan; packs don't include API access
Workflow stops on an API error Include errors in response not ticked Tick it and re-initialize the call
status not offered in expressions Call not initialized, or initialized before a change Initialize again
Bursts of 429 in the backend run Interval too short, or other workflows on the same key Use 1 second or more, or a second key

What it costs

On SimpleVerifier, API access is included in the Pro plan at $29.99 a month, with unlimited email verification and no per-call credits. Email + Phone at $49.99 a month adds live carrier lookups through the same API, if your app collects phone numbers too. If you only need to clean your existing users once, pay-as-you-go packs cost $9 for 2,500 or $19 for 10,000 emails by CSV upload. See pricing.

The short version

Add the API to Bubble's API Connector with Private key in header, set to Bearer plus your key. Create a POST Action call with an email body parameter and tick Include errors in response. In the sign-up workflow, verify first, show the reason and terminate when the status is invalid, and otherwise sign the user up and save the result. Verify existing users with Schedule API workflow on a list at a 1-second interval, or upload a CSV for big user bases.

Common questions

Does Bubble verify email addresses?

Not on its own. Confirming that a mailbox exists needs a DNS lookup and a conversation with the recipient's mail server. In Bubble, you get that by calling an email verification API from the API Connector and branching on the status it returns.

Is my API key safe in Bubble's API Connector?

Yes, if you use Private key in header or tick Private on the header. Bubble's docs say private values stay on the server and are never sent to the browser. Never put the key in an option set, a page element, a custom state or an initialization default value.

Should the verify call be Data or Action?

Action. A Data call fetches when an element needs it, which can mean a call every time a page renders. An Action call runs once, at the step you choose, such as before Sign the user up.

What happens to a sign-up if the verification API is down?

With Include errors in response ticked, the call returns an error object instead of stopping the workflow. The status field is empty, so the condition status is not invalid is true and the sign-up goes ahead.

How fast can a Bubble backend workflow verify my existing users?

As fast as the interval you set. At 1 second between scheduled workflows, that is about 60 users a minute, or 3,600 an hour. The API allows 120 calls a minute per key, but leaving room protects live sign-ups that share the key.

Verify unlimited addresses for $29.99/month

Real SMTP mailbox checks. No credits, no per-email fees.

Get Started