DEV Community

Emore Ogheneyoma Lawrence
Emore Ogheneyoma Lawrence

Posted on • Updated on

Upgrading Supabase's Email Rate Limits in User Registration: A Practical Guide"

Table of Contents

Introduction

Imagine this: you're building a web application with ReactJS on the frontend and Supabase as your preferred backend solution. You're making progress but suddenly realize you can only send 3 emails per hour on user registration. That sucks, right? Yeah, it does.
In this article, we will dive into how to integrate a React application with Supabase authentication, we will then look into how Supabase's built-in email functionality can become a bottleneck, as it limits the number of emails that can be sent within a given timeframe which can in turn hinder the scalability of your application.
All right, enough talk. Let's dive right in

Prerequisites

This article assumes that you know the basics of using ReactJS. It's also helpful if you're already familiar with integrating and using Supabase, though it's not mandatory. You can follow along even if you're not an expert. If you're here for just the solution, you're in the right place.

What is Supabase and Setting up the Supabase Project

Image description

Like stated on the image above, Supabase is an open source Firebase alternative that offers services like starting or having your own Postgres Database, Authentication, Storage, Realtime subscriptions and so much more. It's designed to help developers build and scale applications quickly and efficiently.

Let's set up a Supabase project. Head over to supabase website and create an account.
You will then be redirected to your dashboard to help create a project.
Here's how the dashboard will look like.
NB: You won't have any projects in it if you're just creating an account

Image description

Click on the New project button and then you'll be asked to fill the following below:

Image description

Proceed to click on the Create new project button. This creates the supabase project.
We are then redirected to our created project on our dashboard and it will look like this:

Image description

Congratualations, we've successfully set up our project on the supabase platform

Integrating Supabase with React JS

I would have loved to show you the full authentication system that includes features like login, logout, and protected routes. We will keep it simple and just focus on overcoming Supabase's email rate limits during registration.

Create a react project using vite using any of the commands below:

npm create vite@latest my-app -- --template react # javascript
npm create vite@latest my-app -- --template react-ts # typescript
Enter fullscreen mode Exit fullscreen mode

After that, you have to install the supabase client library into your project. You can install it using the command below:

cd my-app && npm install @supabase/supabase-js
Enter fullscreen mode Exit fullscreen mode

The command above enters the my-app directory/folder and installs the supabase client library in the project

After this, we would need to create an instance of the supabase client:
Make a folder in your src folder and call it supabase then create a file named supabaseClient.ts and populate it with the code below
NB: use .js if you created a React Javascript project

import { createClient } from "@supabase/supabase-js";

// Create a single supabase client for interacting with Supabase API (authentication, database, storage etc)
export const supabase = createClient(
  import.meta.env.VITE_REACT_APP_SUPABASE_URL,
  import.meta.env.VITE_REACT_APP_SUPABASE_ANON_KEY
);
Enter fullscreen mode Exit fullscreen mode

Let's get started building the User Interface(UI) for the Register page

import { useState } from "react";
import "./Register.css"; 

const Register = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [loadingStatus, setLoadingStatus] = useState(false);

  const handleRegister = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
  };
  return (
    <div className="registerPage">
      <h2>Register</h2>
      <form onSubmit={handleRegister}>
        <div>
          <label htmlFor="email">Email:</label>
          <input
            type="email"
            required
            id="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
        </div>

        <div>
          <label htmlFor="password">Password:</label>
          <input
            type="password"
            required
            id="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
        </div>

        <div>
          <label htmlFor="confirmPassword">Confirm Password:</label>
          <input
            type="password"
            required
            id="confirmPassword"
            value={confirmPassword}
            onChange={(e) => setConfirmPassword(e.target.value)}
          />
        </div>
        <button type="submit">
          {loadingStatus ? "Loading..." : "Register"}
        </button>
      </form>
    </div>
  );
};

export default Register;
Enter fullscreen mode Exit fullscreen mode

This is what we have from the code above:

Image description

Now let's connect our Register page to our Supabase project.
We start by getting our SUPABASE_URL and SUPABASE_ANON_KEY keys from our created supabase project, which in our case is our supabase-article

So to get these keys, navigate to your Project Settings then click on the API link.

Here is a pictorial view of where the keys are:

Image description

Create a .env file in your react root-directory, which in our case is the my-app project. Now copy the keys and put them in a .env file created

VITE_REACT_APP_SUPABASE_URL=<supabase_url>
VITE_REACT_APP_SUPABASE_ANON_KEY=<supabase_anon_key>
Enter fullscreen mode Exit fullscreen mode

Replace supabase_url and supabase_anon_key with the API keys.
NB: Make sure the VITE_REACT_APP_SUPABASE_URL AND VITE_REACT_APP_SUPABASE_ANON_KEY variables are the same as what you used in the supabaseClient.ts file above

Now let us proceed by doing some validations on the handleSubmit function and connect registration page to supabase

Here's the updated code of the handleRegister function:

 const handleRegister = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault(); // prevents page from reloading on submit of form

     setLoadingStatus(true)

// Do your validations here
  if(password !== confirmPassword){
    alert("Passwords do not match");
    setLoadingStatus(false)
    return;
  }

// supabase registration
    try {
        const { data, error } = await supabase.auth.signUp({
          email: email.trim(), // trim() removes white spaces from the text entered
          password: password,
          options:{
            data: {
              // add additional data here            
            }
          }
        })

        if (error){
          throw error
        }

        // check for user email uniqueness
        if (data?.user?.identities?.length === 0) {
          alert("Email already registered. Please try a different email.");
          setLoadingStatus(false);
          return;
        }

        console.log("User data:",data);
        alert("Sign up successful! Check your email for the verification link") 
    } catch (error) {
      console.log("Error signing up:", error)
      // @ts-expect-error("allow")
      alert(error?.message);
      setLoadingStatus(false);
    } finally {
      setLoadingStatus(false);
    }
};
Enter fullscreen mode Exit fullscreen mode

The above code does the following:

  • e.preventDefault() prevents the page from reloading when the form is submitted
  • We are checking if the password and confirmPassword state match. If they do not match, we stop the function from going further using the return keyword.
  • We then use the created supabase instance created by accessing the supabase.auth.signUp() method and we pass in the required data.
  • We then check if the email being used to register has not been used. We know that emails are unique as no two users can have the same email.

If all things go as planned, we would have a registered user in our Supabase users database.
Let's test it out:

Image description

Below is the email we got from supabase asking us to verify our email address:

Image description

Now, once this is all completed, we can then go to Authentication section of your supabase-article project, this is where you'll see a list of registered users.

Image description

Now let us try to register another user:

Image description

This is bad for our application's scalability as we need users to be able to register on our apps for them to be able to use them.
We will look into the error and explore why it exists in the next section.

Exploring the Email Rate Limit Issue

We've seen from the previous section the email rate limit issue firsthand. Despite registering just one user (this can vary, but supabase only sends 3 emails an hour), Supabases's built-in email service quickly hits its limit, throwing errors that prevent further registrations.
Supabase's default email service is designed for TEST MODE use only, as highlighted in their documentation here

Here is a screenshot of what it says:

Image description

Now that we've seen this, let's implement the solution

Implementing the Solution

Head over to your project dashboard, in our case it's our supabase-article then navigate to the Project Settings > Authentication.
Scroll down to the SMTP Settings section. You would see this picture

Image description

The Sender email should be your email or your business email, while your Sender name should be your name, business or product name.

Set the Host to smtp.gmail.com, and you can set the Port Number to 465 or 587

Now the Username should be your email address. The main thing we need is the password. This is gotten from your Gmail security settings

Open your Gmail and Navigate to Account
Image description

Click on the Security option below:
Image description

To get your smtp password, 2-Step Verification is required.
Click on the 2-Step Verification below

Image description

Put on the 2-Step Verification, then scroll down to the App passwords section, you would be prompted with a new screen asking you to enter your App name, you can use supabase-article

Image description

On clicking the Create Project button, you will see the password as shown below. Copy it and save it somewhere as it is shown once. Remove the spaces and use the password in the smtp password field.

Image description

Now that we have all that we need, you can click on the save button

Image description

After we have done this, let us now go and adjust our Email rates
At the top of the SMTP Settings section, you would see the text "Email rates can be adjusted here" as seen in the picture below"

Image description

Click on the here link then you'll be redirected to this page below:

Image description

You can then change the Rate limit for sending emails to any number depending on how well your application will be used.

Scroll to the bottom and click on the save button.

Now let us try registering another user on our application

Image description

Now going to check our email, we see the images below:

Image description

Image description

Hooray 🎉🎉, we've successfully set up and use Gmails Smtp to help us bypass supabase's rate limits.

Conclusion

In this article, we found a workaround around supabase's rate limit. We used gmails smtp to help us bypass the rate limits. Thank you for reading up this point. I ask that you drop a like and share this article with your peers who will benefit from this.

You can check the codebase here

What are your thoughts on Bypassing Supabase's Email Rate Limit? Have you encountered something like this and how did you resolve it? Feel free to share your thoughts in the comments section below.

P.S. I'm currently looking for frontend developer opportunities. If you have any leads or are hiring, feel free to check out my resume or connect with me on LinkedIn. I'd love to hear from you!

Top comments (0)