4

am working on a little project and i did finish all the authentication work but one thing,am wondering how to check if the email is real before going into the process of signup, by the way am using react and Firebase and i did look online and i did find a package called email-existence i did try it and it dose return true if the email is real and false if the email dosent exist but thats not working when i use it with react it return an error

import firebase from '../util/firebase';
const emailExistence = require('email-existence');

export const normalSignup = (props, setSign, email, password, confirmPassword, username) => {
  emailExistence.check(email, function (error, response) { // return error here addresses.sort is not a function
    console.log('res: ' + response);
  });
}

anyway am wondering if there's a way to do it with Firebase without external packages thanx in advance PS:am not using cloud functions

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
scripter
  • 1,211
  • 2
  • 11
  • 21
  • it looks like it's working correctly, you should try and work out what the error is. is it `addresses.sort is not a function` ? – Red Baron Jun 12 '20 at 13:28
  • yes that's exactly the error , i did try that in external project and i did run it with node and it did work but its not working in a react project @RedBaron – scripter Jun 12 '20 at 13:30
  • well something is trying to run `addresses.sort` so try and figure that out OR why not use this package instead? https://www.npmjs.com/package/email-validator has many more downloads which is a good sign it's well used and should be easy to integrate – Red Baron Jun 12 '20 at 13:32
  • 1
    ok i will try that @RedBaron – scripter Jun 12 '20 at 13:36
  • I can say that's easy to check if it's a valid email pattern, there are some fancy regex like here: [regex to validate email](https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript). nevertheless, they check if it's a valid pattern, not a valid provider. an email misspelled like `john@gnail.com` will pass the validation. If you have mailchimp (that's used more for targeting audiences) they actually have a solid system that tells that `gnail` is not valid (maybe there others with that quality of assertion but I'm not aware of). – buzatto Jun 12 '20 at 13:38
  • The problem is: you can't just run Node (backend) code like this in your client React app (as I suppose it is a client app without node backend if you are on Firebase). See my solution below about using an external api with fetch (or axios if you prefer). Note: email-existence package gives a lot of false negatives, even my own email was invalid according to them :) – theDavidBarton Jun 12 '20 at 17:14

3 Answers3

2

Well assuming you want to check if the email is a verified email address you can write the code in the following way

import firebase from '../util/firebase';
const App = {
  firebase: firebase,
  getLoggedInUser: () => {
    const currentUser = App.firebase.auth().currentUser
    if (currentUser) {
      return {
        email: currentUser.email,
        userId: currentUser.uid,
        isEmailVerified: currentUser.emailVerified
      }
    } else {
      return undefined
    }
  },
  isAuthenticated: () => {
    return (App.getLoggedInUser() && App.getLoggedInUser().isEmailVerified)
  },
  authenticate: async (email, password) => {
    await App.firebase.auth().signInWithEmailAndPassword(email, password)
  },
  signup: async (email, password) => {
    const userCredential = await App.firebase.auth().createUserWithEmailAndPassword(email, password)
    await userCredential.user.sendEmailVerification()
    return `Check your email for verification mail before logging in`
  },

Here the following happens

  • When a user signs up the signup method is called and an email verification is sent by firebase as shown in the above code
  • When a user logs in the authenticate method is called so according to firebase you are logged in
  • However to redirect or render a certain page say after log in you can use the isAuthenticated method to display a page to a certain user
  • So you can pass method isAuthenticated as a prop to react-router and render your web application how you want.
  • This way only real and authentic email id which are verified will have access to your app

Note

This method is working already in prod but its using VueJS and is an opensource project on github let me know if you want to reference it

Phil
  • 435
  • 2
  • 9
  • 28
  • 1
    that's cool but its still not what i exactly need coz think about it this way the user will be able to store a dummy email in your database , even if i set it up that the user cant login without email verification i still have his info in my database and i dont want that i want to stop the signup process if the email is not real so ill try to achieve that with cloud functions :) – scripter Jun 12 '20 at 14:43
  • @Scripts that is surely the way to go, What you can do is run a cloud function using a cron expression daily which `getsListOfUsersInTheDatabase` and deletes all the users which have the emailVerified property as false. that way your database wont contain bad email addresses check out the firebase admin sdk here https://firebase.google.com/docs/auth/admin/manage-users – Phil Jun 12 '20 at 19:56
  • You can get the user details in your cloud function with this method `admin.auth().getUsers([])` of the `firebase-admin sdk` – Phil Jun 12 '20 at 20:01
1

Maybe just use a regex to check if the email is valid?

According to this webpage for JavaScript you just need:

const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

if (emailRegex.test(email)) {
    console.log('Email valid!');
}

This won't stop people entering emails for incorrect domains, but ensures that if someone uses a mail server that isn't widely known, it will get accepted too.

Adam Jeliński
  • 1,708
  • 1
  • 10
  • 21
  • am not checking for the format of the email brother i want to check if the email is real one because i already did check for the format :) – scripter Jun 12 '20 at 13:43
  • The only way you can check if the email is real is to send a mail to it and it does not bounces. And apparently if you are sending a mail just for verifying if it is real, it is better to verify if it belongs to the same user - which is essentially the work of firebase too. – frunkad Jun 12 '20 at 13:50
  • 1
    A widely accepted method is just to validate the format of email as Adam mentioned and send a verification mail to it via firebase. – frunkad Jun 12 '20 at 13:51
  • 2
    It's not possible to check if the email actually exists just from the frontend, because browsers don't have an API to send emails directly. As proposed by @frunkad, you should use Firebase to send a verification email. – Adam Jeliński Jun 12 '20 at 13:56
0

Your only option on the client side (if you are on Firebase I suppose you don't have the luxury to run a Node backend) to fetch a similar service as email-existence which returns a "valid" or "invalid" response if you GET the endpoint with the email address.

These are usually premium services, but if you have low traffic you can try out a free one. In my example it is Mailboxlayer. Their endpoint can be called like this (and of course if you are stick to the client side it means anyone can steal your api key from production via browser network tab!):

GET http://apilayer.net/api/check?access_key=YOUR_ACCESS_KEY&email=richard@example.com

Which returns a JSON:

{
  "email": "richard@example.com",
  "did_you_mean": "",
  "user": "support",
  "domain": "apilayer.net",
  "format_valid": true,
  "mx_found": true,
  "smtp_check": true,
  "catch_all": false,
  "role": true,
  "disposable": false,
  "free": false,
  "score": 0.8
}   

Best to use score, which:

[...] returns a numeric score between 0 and 1 reflecting the quality and deliverability of the requested email address.

In React:

  const [data, setData] = useState(null)
  const [emailToVerify, setEmailToVerify] = useState('richard@example.com') // just for the sake of example
  const apiKey = process.env.API_KEY

  const fetchEmailVerificationApi = useCallback(async () => {
    try {
      const response = await fetch(`http://apilayer.net/api/check?access_key=${apiKey}&email=${emailToVerify}`)
      const json = await response.json()
      setData(json.score) // returns a numeric score between 0 and 1 reflecting the quality and deliverability of the requested email address.
    } catch (e) {
      console.error(e)
    }
  }, [apiKey, emailToVerify])

  useEffect(() => {
    fetchEmailVerificationApi()
  }, [fetchEmailVerificationApi])
theDavidBarton
  • 7,643
  • 4
  • 24
  • 51