Rust Email Validation
Complete guide to email validation in Rust
What You'll Learn
- Integrate VerifyForge API using reqwest
- Create type-safe validation functions
- Handle errors with Result types
- Implement async validation
- Best practices for production
Prerequisites
- Rust 1.70+ installed
- Basic knowledge of Rust
- VerifyForge API key (get free key)
Installation
# Cargo.toml
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
Quick Start
use reqwest::Client;
use serde::Deserialize;
#[derive(Deserialize)]
struct ValidationData {
#[serde(rename = "isValid")]
is_valid: bool,
reachability: String,
}
#[derive(Deserialize)]
struct ValidationResponse {
data: ValidationData,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let api_key = "your_api_key";
let email = "user@example.com";
let response = client
.get(&format!("https://verifyforge.com/api/validate?email={}", email))
.header("X-API-Key", api_key)
.send()
.await?
.json::<ValidationResponse>()
.await?;
println!("Valid: {}", response.data.is_valid);
Ok(())
}
Email Validator Module
// src/email_validator.rs
use reqwest::{Client, Error};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
pub struct ValidationResult {
pub email: String,
#[serde(rename = "isValid")]
pub is_valid: bool,
pub reachability: String,
pub disposable: bool,
#[serde(rename = "roleAccount")]
pub role_account: bool,
#[serde(rename = "freeProvider")]
pub free_provider: bool,
pub suggestion: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ValidationResponse {
pub success: bool,
pub data: ValidationResult,
}
#[derive(Debug, Serialize)]
struct BulkRequest {
emails: Vec<String>,
}
pub struct EmailValidator {
client: Client,
api_key: String,
base_url: String,
}
impl EmailValidator {
pub fn new(api_key: String) -> Self {
Self {
client: Client::new(),
api_key,
base_url: "https://verifyforge.com".to_string(),
}
}
pub async fn validate(&self, email: &str) -> Result<ValidationResult, Error> {
let url = format!("{}/api/validate?email={}", self.base_url, email);
let response = self
.client
.get(&url)
.header("X-API-Key", &self.api_key)
.send()
.await?
.json::<ValidationResponse>()
.await?;
Ok(response.data)
}
pub async fn validate_bulk(&self, emails: Vec<String>) -> Result<Vec<ValidationResult>, Error> {
let url = format!("{}/api/validate/bulk", self.base_url);
let payload = BulkRequest { emails };
let response = self
.client
.post(&url)
.header("X-API-Key", &self.api_key)
.header("Content-Type", "application/json")
.json(&payload)
.send()
.await?
.json::<serde_json::Value>()
.await?;
let results = response["data"]["results"]
.as_array()
.unwrap()
.iter()
.map(|v| serde_json::from_value(v.clone()).unwrap())
.collect();
Ok(results)
}
pub async fn is_valid(&self, email: &str) -> bool {
match self.validate(email).await {
Ok(result) => result.is_valid,
Err(_) => false,
}
}
}
Actix Web Example
use actix_web::{post, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
mod email_validator;
use email_validator::EmailValidator;
#[derive(Deserialize)]
struct ValidateRequest {
email: String,
}
#[derive(Serialize)]
struct ApiResponse {
success: bool,
data: Option<serde_json::Value>,
error: Option<String>,
}
#[post("/api/validate")]
async fn validate(
req: web::Json<ValidateRequest>,
validator: web::Data<Arc<EmailValidator>>,
) -> impl Responder {
match validator.validate(&req.email).await {
Ok(result) => HttpResponse::Ok().json(ApiResponse {
success: true,
data: Some(serde_json::to_value(result).unwrap()),
error: None,
}),
Err(_) => HttpResponse::InternalServerError().json(ApiResponse {
success: false,
data: None,
error: Some("Validation failed".to_string()),
}),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let api_key = std::env::var("VERIFYFORGE_API_KEY").expect("API key not set");
let validator = Arc::new(EmailValidator::new(api_key));
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(validator.clone()))
.service(validate)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
Concurrent Validation
use futures::future::join_all;
pub async fn validate_many(
validator: &EmailValidator,
emails: Vec<String>,
) -> Vec<(String, bool)> {
let futures = emails.iter().map(|email| {
let email = email.clone();
async move {
let is_valid = validator.is_valid(&email).await;
(email, is_valid)
}
});
join_all(futures).await
}
