Code Examples

Ready-to-use code examples for integrating ValidMail into your applications in multiple languages.

JS

JavaScript / Node.js

Basic Email Verification

// Using fetch (Node.js 18+ or browser)
async function verifyEmail(email) {
  const response = await fetch('https://validmail.io/api/v1/verify', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.VALIDMAIL_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ email }),
  });

  if (!response.ok) {
    throw new Error(`Verification failed: ${response.status}`);
  }

  return response.json();
}

// Usage
const result = await verifyEmail('user@example.com');
console.log(result.status); // 'valid', 'invalid', 'risky', or 'unknown'
console.log(result.score);  // 0-100

With Axios and Error Handling

import axios from 'axios';

const validmail = axios.create({
  baseURL: 'https://validmail.io/api/v1',
  headers: {
    'Authorization': `Bearer ${process.env.VALIDMAIL_API_KEY}`,
    'Content-Type': 'application/json',
  },
});

async function verifyEmail(email) {
  try {
    const { data } = await validmail.post('/verify', { email });
    return data;
  } catch (error) {
    if (error.response) {
      const { code, message } = error.response.data.error;

      if (code === 'RATE_LIMITED') {
        const retryAfter = error.response.headers['retry-after'];
        throw new Error(`Rate limited. Retry after ${retryAfter}s`);
      }

      throw new Error(`${code}: ${message}`);
    }
    throw error;
  }
}

// Batch verification with concurrency control
async function verifyEmails(emails, concurrency = 5) {
  const results = [];

  for (let i = 0; i < emails.length; i += concurrency) {
    const batch = emails.slice(i, i + concurrency);
    const batchResults = await Promise.all(
      batch.map(email => verifyEmail(email).catch(err => ({
        email,
        status: 'error',
        error: err.message,
      })))
    );
    results.push(...batchResults);

    // Small delay between batches to respect rate limits
    if (i + concurrency < emails.length) {
      await new Promise(r => setTimeout(r, 200));
    }
  }

  return results;
}

Express.js Middleware

import express from 'express';

const app = express();
app.use(express.json());

// Middleware to validate email in request body
async function validateEmail(req, res, next) {
  const { email } = req.body;

  if (!email) {
    return res.status(400).json({ error: 'Email is required' });
  }

  try {
    const response = await fetch('https://validmail.io/api/v1/verify', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.VALIDMAIL_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ email }),
    });

    const result = await response.json();

    if (result.status === 'invalid') {
      return res.status(400).json({
        error: 'Invalid email address',
        details: result.verdict,
      });
    }

    // Attach validation result to request
    req.emailValidation = result;
    next();
  } catch (error) {
    // Don't block on verification errors
    console.error('Email validation error:', error);
    next();
  }
}

// Use in routes
app.post('/signup', validateEmail, (req, res) => {
  const { email } = req.body;
  const validation = req.emailValidation;

  // Proceed with signup, maybe warn for risky emails
  if (validation?.status === 'risky') {
    console.log(`Warning: Risky email signup: ${email}`);
  }

  // ... signup logic
});
PY

Python

Basic Verification

import os
import requests

def verify_email(email: str) -> dict:
    """Verify a single email address."""
    response = requests.post(
        'https://validmail.io/api/v1/verify',
        headers={
            'Authorization': f'Bearer {os.environ["VALIDMAIL_API_KEY"]}',
            'Content-Type': 'application/json',
        },
        json={'email': email},
        timeout=30
    )
    response.raise_for_status()
    return response.json()

# Usage
result = verify_email('user@example.com')
print(f"Status: {result['status']}")
print(f"Score: {result['score']}")

Class-based Client with Retry Logic

import os
import time
import requests
from typing import Optional, List, Dict
from dataclasses import dataclass

@dataclass
class VerificationResult:
    email: str
    status: str
    score: int
    verdict: str
    checks: dict

class ValidMailClient:
    def __init__(self, api_key: Optional[str] = None):
        self.api_key = api_key or os.environ.get('VALIDMAIL_API_KEY')
        self.base_url = 'https://validmail.io/api/v1'
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {self.api_key}',
            'Content-Type': 'application/json',
        })

    def verify(self, email: str, retries: int = 3) -> VerificationResult:
        """Verify email with automatic retry on rate limits."""
        for attempt in range(retries):
            response = self.session.post(
                f'{self.base_url}/verify',
                json={'email': email},
                timeout=30
            )

            if response.status_code == 429:
                retry_after = int(response.headers.get('Retry-After', 60))
                time.sleep(retry_after)
                continue

            response.raise_for_status()
            data = response.json()

            return VerificationResult(
                email=data['email'],
                status=data['status'],
                score=data['score'],
                verdict=data['verdict'],
                checks=data['checks']
            )

        raise Exception('Max retries exceeded')

    def verify_batch(self, emails: List[str]) -> List[VerificationResult]:
        """Verify multiple emails."""
        results = []
        for email in emails:
            try:
                result = self.verify(email)
                results.append(result)
            except Exception as e:
                results.append(VerificationResult(
                    email=email,
                    status='error',
                    score=0,
                    verdict=str(e),
                    checks={}
                ))
            time.sleep(0.1)  # Rate limiting
        return results

# Usage
client = ValidMailClient()
result = client.verify('user@example.com')
print(f"{result.email}: {result.status} ({result.score})")

Django Integration

# validators.py
import requests
from django.conf import settings
from django.core.exceptions import ValidationError

def validate_email_deliverable(email):
    """Django validator for email deliverability."""
    try:
        response = requests.post(
            'https://validmail.io/api/v1/verify',
            headers={
                'Authorization': f'Bearer {settings.VALIDMAIL_API_KEY}',
                'Content-Type': 'application/json',
            },
            json={'email': email},
            timeout=10
        )

        result = response.json()

        if result['status'] == 'invalid':
            raise ValidationError(
                f'This email address is invalid: {result["verdict"]}'
            )

        if result['checks'].get('disposable'):
            raise ValidationError(
                'Disposable email addresses are not allowed'
            )

    except requests.RequestException:
        # Don't block on network errors
        pass

# models.py
from django.db import models
from .validators import validate_email_deliverable

class User(models.Model):
    email = models.EmailField(
        unique=True,
        validators=[validate_email_deliverable]
    )
    # ... other fields

# forms.py
from django import forms
from .validators import validate_email_deliverable

class SignupForm(forms.Form):
    email = forms.EmailField(validators=[validate_email_deliverable])
    password = forms.CharField(widget=forms.PasswordInput)
PHP

PHP

Basic Verification

<?php

function verifyEmail(string $email): array {
    $apiKey = getenv('VALIDMAIL_API_KEY');

    $ch = curl_init('https://validmail.io/api/v1/verify');

    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode(['email' => $email]),
        CURLOPT_TIMEOUT => 30,
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode !== 200) {
        throw new Exception("Verification failed: HTTP $httpCode");
    }

    return json_decode($response, true);
}

// Usage
try {
    $result = verifyEmail('user@example.com');
    echo "Status: " . $result['status'] . "\n";
    echo "Score: " . $result['score'] . "\n";
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}

Laravel Integration

<?php
// app/Services/ValidMailService.php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;

class ValidMailService
{
    protected string $apiKey;
    protected string $baseUrl = 'https://validmail.io/api/v1';

    public function __construct()
    {
        $this->apiKey = config('services.validmail.key');
    }

    public function verify(string $email): array
    {
        // Cache results for 24 hours
        return Cache::remember(
            'email_verification_' . md5($email),
            now()->addHours(24),
            fn() => $this->doVerify($email)
        );
    }

    protected function doVerify(string $email): array
    {
        $response = Http::withToken($this->apiKey)
            ->timeout(30)
            ->post("{$this->baseUrl}/verify", [
                'email' => $email,
            ]);

        if ($response->status() === 429) {
            $retryAfter = $response->header('Retry-After', 60);
            throw new \Exception("Rate limited. Retry after {$retryAfter}s");
        }

        $response->throw();
        return $response->json();
    }
}

// app/Rules/DeliverableEmail.php

namespace App\Rules;

use App\Services\ValidMailService;
use Illuminate\Contracts\Validation\Rule;

class DeliverableEmail implements Rule
{
    protected string $message = 'This email address is not valid.';

    public function passes($attribute, $value): bool
    {
        try {
            $service = app(ValidMailService::class);
            $result = $service->verify($value);

            if ($result['status'] === 'invalid') {
                $this->message = $result['verdict'];
                return false;
            }

            if ($result['checks']['disposable'] ?? false) {
                $this->message = 'Disposable emails are not allowed.';
                return false;
            }

            return true;
        } catch (\Exception $e) {
            // Log error but don't block
            \Log::warning('Email verification failed', ['error' => $e->getMessage()]);
            return true;
        }
    }

    public function message(): string
    {
        return $this->message;
    }
}

// Usage in controller
public function register(Request $request)
{
    $request->validate([
        'email' => ['required', 'email', new DeliverableEmail],
        'password' => ['required', 'min:8'],
    ]);
    // ...
}
RB

Ruby

Basic Verification with HTTParty

require 'httparty'

class ValidMail
  include HTTParty
  base_uri 'https://validmail.io/api/v1'

  def initialize(api_key = ENV['VALIDMAIL_API_KEY'])
    @api_key = api_key
  end

  def verify(email)
    response = self.class.post('/verify',
      headers: {
        'Authorization' => "Bearer #{@api_key}",
        'Content-Type' => 'application/json'
      },
      body: { email: email }.to_json,
      timeout: 30
    )

    raise "Verification failed: #{response.code}" unless response.success?
    response.parsed_response
  end
end

# Usage
client = ValidMail.new
result = client.verify('user@example.com')
puts "Status: #{result['status']}"
puts "Score: #{result['score']}"

Rails ActiveModel Validator

# app/validators/deliverable_email_validator.rb

class DeliverableEmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    return if value.blank?

    result = verify_email(value)

    case result['status']
    when 'invalid'
      record.errors.add(attribute, result['verdict'])
    when 'risky'
      if result.dig('checks', 'disposable')
        record.errors.add(attribute, 'disposable emails are not allowed')
      end
    end
  rescue => e
    Rails.logger.warn "Email verification failed: #{e.message}"
    # Don't block on errors
  end

  private

  def verify_email(email)
    Rails.cache.fetch("email_verification_#{email}", expires_in: 24.hours) do
      response = HTTParty.post(
        'https://validmail.io/api/v1/verify',
        headers: {
          'Authorization' => "Bearer #{ENV['VALIDMAIL_API_KEY']}",
          'Content-Type' => 'application/json'
        },
        body: { email: email }.to_json,
        timeout: 30
      )
      response.parsed_response
    end
  end
end

# app/models/user.rb
class User < ApplicationRecord
  validates :email, presence: true, deliverable_email: true
end
GO

Go

HTTP Client

package validmail

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "time"
)

type Client struct {
    apiKey     string
    baseURL    string
    httpClient *http.Client
}

type VerifyRequest struct {
    Email string `json:"email"`
}

type VerifyResponse struct {
    Email   string                 `json:"email"`
    Status  string                 `json:"status"`
    Score   int                    `json:"score"`
    Verdict string                 `json:"verdict"`
    Checks  map[string]interface{} `json:"checks"`
}

func NewClient(apiKey string) *Client {
    if apiKey == "" {
        apiKey = os.Getenv("VALIDMAIL_API_KEY")
    }
    return &Client{
        apiKey:  apiKey,
        baseURL: "https://validmail.io/api/v1",
        httpClient: &http.Client{
            Timeout: 30 * time.Second,
        },
    }
}

func (c *Client) Verify(email string) (*VerifyResponse, error) {
    body, _ := json.Marshal(VerifyRequest{Email: email})

    req, err := http.NewRequest("POST", c.baseURL+"/verify", bytes.NewBuffer(body))
    if err != nil {
        return nil, err
    }

    req.Header.Set("Authorization", "Bearer "+c.apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := c.httpClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        return nil, fmt.Errorf("verification failed: %d", resp.StatusCode)
    }

    var result VerifyResponse
    if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
        return nil, err
    }

    return &result, nil
}

// Usage
func main() {
    client := NewClient("")
    result, err := client.Verify("user@example.com")
    if err != nil {
        panic(err)
    }
    fmt.Printf("Status: %s, Score: %d\n", result.Status, result.Score)
}

cURL

Single Email Verification

curl -X POST https://validmail.io/api/v1/verify \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'

Bulk Verification

# Create bulk job
curl -X POST https://validmail.io/api/v1/bulk \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": ["user1@example.com", "user2@example.com"],
    "name": "My List"
  }'

# Check status
curl https://validmail.io/api/v1/bulk/bulk_abc123 \
  -H "Authorization: Bearer YOUR_API_KEY"

# Download results
curl https://validmail.io/api/v1/bulk/bulk_abc123/download \
  -H "Authorization: Bearer YOUR_API_KEY"