Integrate e-mail validation by Abstract API to a form [React]
As a solution for preventing spam from your comment form or contact form, we can use validating API services that check whether the entered e-mail exists or not.
Because these APIs can check e-mails in real-time, it can hugely reduce spam if you make the submit button active just when the e-mail is validated.
*The demo above can check 100 e-mails per month (free tier). If it doesn't work, it can exceed the limit.
React Hook to use: useState()
and useRef()
Working environment:
- Node.js v18.12.1
- React v18.2.0
Sign up for the API
This time, we're going to use Abstract API.
Their free tier includes 100 validation per month. It would be enough for a personal blog.
Make a form Component
I'd add a validation function inside a form component just for the explanation. It's better if the validation function is separated as another component.
The form
const Form = () => {
return (
<form>
<input
id="email"
name="email"
type="email"
required
/>
</form>
)
}
export default Form
Get the e-mail input value
With useRef()
, get the value inputted on the form.
import { useRef } from "react"
const Form = () => {
const emailRef = useRef()
return (
<form>
<input
id="email"
name="email"
type="email"
required
ref={emailRef}
/>
</form>
)
}
export default Form
You can get the value with emailRef.current.value
.
A constant to judge whether the value is e-mail format
To avoid unnecessary validations, prepare a constant of the e-mail format and make the function work only when the input value meets it.
const pattern = /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]+.[A-Za-z0-9]+$/
Make the function work when the focus is blurred
Add a state
With useState()
, add a constant of;
emailIsValid
: whether the input value (= e-mail) is valid or not (defaultfalse
)
Only when the entered e-mail is valid, make the state true
. *we'll do it later.
import { useRef, useState } from "react"
//...
const Form = () => {
const emailRef = useRef()
const [emailIsValid, setEmailIsValid] = useState(false)
//...
return {
//...
}
}
Add a handler
Now let's add a handler to judge the entered e-mail when the focus is blurred from the input
tag. It's an onBlur
event to use.
Plus, let the handler work only when the entered value meets the constant pattern
so that some unnecessary validations won't run.
By emailRef
set with a React Hook useRef()
, you can get the current value as emailRef.current.value
. So, check whether the value meets the constant pattern
using the test()
method of javascript.
pattern.test(emailRef.current.value)
Reference RegExp.prototype.test() - JavaScript - MDN Web Docs - Mozilla
The handler name below is up to you. async
is added because of the asynchronous communication with the API.
import { useRef, useState } from "react"
const pattern = /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]+.[A-Za-z0-9]+$/
const Form = () => {
//...
const emailCheckHandler = async () => {
if (pattern.test(emailRef)) {
// validation challenge here
if () { // when passed
setEmailIsValid(true)
} else { // when failed
setEmailIsValid(false)
}
}
}
return (
<form>
<input
id="email"
name="email"
type="email"
required
ref={emailRef}
onBlur={emailCheckHandler}
/>
</form>
)
}
export default Form
Validation challenge with Abstract API
Now use fetch()
to connect to Abstract API.
With Abstract API, the result of the validation is returned on the following URL;
https://emailvalidation.abstractapi.com/v1/?api_key=[API_KEY]&email=[EMAIL_TO_VALIDATE]
The steps to get the response:
const url = "https://emailvalidation.abstractapi.com/v1/?api_key=[API_KEY]&email=[EMAIL_TO_VALIDATE]"
const response = await fetch(url)
const data = await response.json()
The response itself can be visible with console.log(data)
;
{
"email": "[email protected]",
"autocorrect": "",
"deliverability": "DELIVERABLE",
"quality_score": "0.80",
"is_valid_format": {
"value": true,
"text": "TRUE"
},
"is_free_email": {
"value": false,
"text": "FALSE"
},
"is_disposable_email": {
"value": false,
"text": "FALSE"
},
"is_role_email": {
"value": false,
"text": "FALSE"
},
"is_catchall_email": {
"value": true,
"text": "TRUE"
},
"is_mx_found": {
"value": true,
"text": "TRUE"
},
"is_smtp_valid": {
"value": true,
"text": "TRUE"
}
}
The e-mail validation by Abstract API is given by quality_score
between 0.01 and 0.99.
As I put the response in the constant data
above, the score can be retrieved with data.quality_score
.
In my environment, it returns 0.7 for a Gmail address. Just try it with some e-mail addresses and find your point where the challenge can pass.
The check handler would be like the following. Do not expose your API key but keep it inside .env
.
const emailCheckHandler = async () => {
if (pattern.test(emailRef.current.value)) {
const url = `https://emailvalidation.abstractapi.com/v1/?api_key=${process.env.ABSTRACT_API_KEY}&email=${emailRef.current.value}`
const response = await fetch(url)
const data = await response.json()
if (data.quality_score >= 0.7) {// OK
setEmailIsValid(true)
} else {// Failed
setEmailIsValid(false)
}
}
}
Because the API key must work on the client side, you'll need to add a prefix in the case of Next.js or Gatsby.js.;
# Next.js
NEXT_PUBLIC_ABSTRACT_API=xxxxxxxxxxxxxxxxx
# Gatsby.js
GATSBY_ABSTRACT_API=xxxxxxxxxxxxxxxxx
The code
import { useRef, useState } from "react"
const pattern = /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]+.[A-Za-z0-9]+$/
const Form = () => {
const emailRef = useRef()
const [emailIsValid, setEmailIsValid] = useState(false)
const emailCheckHandler = async () => {
if (pattern.test(emailRef.current.value)) {
const url = `https://emailvalidation.abstractapi.com/v1/?api_key=${process.env.ABSTRACT_API}&email=${emailRef.current.value}`
const response = await fetch(url)
const data = await response.json()
if (data.quality_score >= 0.7) {
setEmailIsValid(true)
} else {
setEmailIsValid(false)
}
}
}
return (
<form>
<input
id="email"
name="email"
type="email"
required
ref={emailRef}
onBlur={emailCheckHandler}
/>
</form>
)
}
export default Form
Make the form more practical
The form would be more secure with reCaptcha, etc.
- Integration of reCaptcha or hCaptcha (security)
- Activate the submit button after e-mail validation and reCaptcha challenge (security)
- Show a spinner during the e-mail validation (UX)
There are some other points to take care of about the Form. Abstract official guidance would be helpful for it.
That's it!