Validazione Record MX: Guida per Sviluppatori

Leo
LeoFounder, BillionVerify

Validazione record MX: ricerche DNS, parsing, gestione priorità e best practice verifica domini email.

Cover Image for Validazione Record MX: Guida per Sviluppatori

Ogni email che invii viaggia attraverso una rete di server accuratamente orchestrata, e i record Mail Exchange (MX) sono i segnali che guidano questo percorso. Comprendere come validare i record MX è una competenza fondamentale per qualsiasi sviluppatore che costruisce sistemi di verifica email, moduli di contatto o applicazioni che raccolgono indirizzi email. Questa guida completa esplora la validazione dei record MX dai concetti base alle strategie di implementazione avanzate, fornendoti le conoscenze per integrare una verifica email robusta nelle tue applicazioni.

Comprendere i Record MX

I record Mail Exchange sono record DNS che specificano quali server di posta sono responsabili dell'accettazione delle email per conto di un dominio. Quando invii un'email a user@example.com, il tuo server di posta deve sapere dove consegnarla. I record MX forniscono questa informazione puntando ai server di posta del dominio.

Come Funzionano i Record MX

Quando viene inviata un'email, il server di posta mittente esegue una ricerca DNS per trovare i record MX del dominio del destinatario. Questa ricerca restituisce uno o più hostname di server di posta insieme a valori di priorità che indicano l'ordine di preferenza.

Una tipica ricerca di record MX per gmail.com potrebbe restituire:

gmail.com.    MX    5     gmail-smtp-in.l.google.com.
gmail.com.    MX    10    alt1.gmail-smtp-in.l.google.com.
gmail.com.    MX    20    alt2.gmail-smtp-in.l.google.com.
gmail.com.    MX    30    alt3.gmail-smtp-in.l.google.com.
gmail.com.    MX    40    alt4.gmail-smtp-in.l.google.com.

Il server mittente tenta la consegna prima al server con priorità più bassa (in questo caso, priorità 5). Se quel server non è disponibile, prova il livello di priorità successivo, e così via. Questa ridondanza garantisce la consegna dell'email anche quando singoli server sono inattivi.

Componenti dei Record MX

Ogni record MX contiene due informazioni essenziali:

Priorità (Preferenza)

Un valore numerico che indica l'ordine in cui devono essere provati i server di posta. Numeri più bassi indicano priorità più alta. I server con la stessa priorità vengono provati in ordine casuale, fornendo bilanciamento del carico.

Hostname del Server di Posta

Il nome di dominio completamente qualificato (FQDN) del server di posta che gestisce l'email per il dominio. Questo hostname deve risolversi in un indirizzo IP tramite un record A o AAAA.

Perché i Record MX Sono Importanti per la Verifica Email

La validazione dei record MX serve come punto di controllo critico nel processo di verifica email:

Conferma dell'Esistenza del Dominio

Se un dominio non ha record MX, tipicamente non può ricevere email. Alcuni domini potrebbero avere un fallback con record A, ma l'assenza di record MX è spesso un forte indicatore che il dominio non è configurato per l'email.

Verifica dell'Infrastruttura

Record MX validi che si risolvono in server di posta funzionanti indicano che il dominio ha un'infrastruttura email in atto. Questo non garantisce che un indirizzo specifico esista, ma conferma che il dominio può ricevere email.

Rilevamento Spam e Frodi

Le aziende legittime mantengono record MX appropriati. I domini sospetti usati per spam o frodi spesso hanno record MX configurati in modo errato o mancanti.

Ottimizzazione delle Prestazioni

Controllare i record MX prima di tentare la verifica SMTP evita tempo sprecato connettendosi a domini che non possono ricevere email.

Implementare Ricerche Record MX

Esploriamo come implementare la validazione dei record MX in diversi ambienti di programmazione.

Implementazione Node.js

Node.js fornisce risoluzione DNS integrata tramite il modulo dns:

const dns = require('dns').promises;

async function getMxRecords(domain) {
  try {
    const records = await dns.resolveMx(domain);

    // Sort by priority (lowest first)
    records.sort((a, b) => a.priority - b.priority);

    return {
      success: true,
      domain,
      records: records.map(r => ({
        exchange: r.exchange,
        priority: r.priority
      }))
    };
  } catch (error) {
    return {
      success: false,
      domain,
      error: error.code,
      message: getMxErrorMessage(error.code)
    };
  }
}

function getMxErrorMessage(code) {
  const messages = {
    'ENODATA': 'No MX records found for this domain',
    'ENOTFOUND': 'Domain does not exist',
    'ETIMEOUT': 'DNS lookup timed out',
    'ESERVFAIL': 'DNS server failed to respond'
  };
  return messages[code] || 'Unknown DNS error';
}

// Usage
const result = await getMxRecords('gmail.com');
console.log(result);

Implementazione Python

Il modulo dns.resolver di Python dalla libreria dnspython fornisce capacità complete di ricerca DNS:

import dns.resolver
import dns.exception

def get_mx_records(domain):
    try:
        answers = dns.resolver.resolve(domain, 'MX')

        records = []
        for rdata in answers:
            records.append({
                'exchange': str(rdata.exchange).rstrip('.'),
                'priority': rdata.preference
            })

        # Sort by priority
        records.sort(key=lambda x: x['priority'])

        return {
            'success': True,
            'domain': domain,
            'records': records
        }

    except dns.resolver.NXDOMAIN:
        return {
            'success': False,
            'domain': domain,
            'error': 'NXDOMAIN',
            'message': 'Domain does not exist'
        }

    except dns.resolver.NoAnswer:
        return {
            'success': False,
            'domain': domain,
            'error': 'NoAnswer',
            'message': 'No MX records found for this domain'
        }

    except dns.exception.Timeout:
        return {
            'success': False,
            'domain': domain,
            'error': 'Timeout',
            'message': 'DNS lookup timed out'
        }

# Usage
result = get_mx_records('gmail.com')
print(result)

Implementazione Go

Il pacchetto net di Go fornisce funzioni di ricerca DNS semplici:

package main

import (
    "fmt"
    "net"
    "sort"
)

type MxResult struct {
    Success bool
    Domain  string
    Records []MxRecord
    Error   string
}

type MxRecord struct {
    Exchange string
    Priority uint16
}

func getMxRecords(domain string) MxResult {
    records, err := net.LookupMX(domain)

    if err != nil {
        return MxResult{
            Success: false,
            Domain:  domain,
            Error:   err.Error(),
        }
    }

    if len(records) == 0 {
        return MxResult{
            Success: false,
            Domain:  domain,
            Error:   "No MX records found",
        }
    }

    // Sort by priority
    sort.Slice(records, func(i, j int) bool {
        return records[i].Pref < records[j].Pref
    })

    result := MxResult{
        Success: true,
        Domain:  domain,
        Records: make([]MxRecord, len(records)),
    }

    for i, r := range records {
        result.Records[i] = MxRecord{
            Exchange: r.Host,
            Priority: r.Pref,
        }
    }

    return result
}

func main() {
    result := getMxRecords("gmail.com")
    fmt.Printf("%+v\n", result)
}

Tecniche Avanzate di Validazione MX

Le ricerche MX di base confermano l'esistenza dei record, ma la validazione email completa richiede un'analisi più approfondita.

Validare la Connettività del Server di Posta

I record MX puntano a hostname che devono risolversi in indirizzi IP. Verifica che i server di posta siano effettivamente raggiungibili:

const dns = require('dns').promises;
const net = require('net');

async function validateMxConnectivity(domain) {
  // Get MX records
  const mxResult = await getMxRecords(domain);

  if (!mxResult.success) {
    return mxResult;
  }

  // Validate each mail server
  const validatedRecords = [];

  for (const record of mxResult.records) {
    const validation = await validateMailServer(record.exchange);
    validatedRecords.push({
      ...record,
      ...validation
    });
  }

  return {
    success: true,
    domain,
    records: validatedRecords,
    hasReachableServer: validatedRecords.some(r => r.reachable)
  };
}

async function validateMailServer(hostname) {
  try {
    // Resolve hostname to IP
    const addresses = await dns.resolve4(hostname);

    if (addresses.length === 0) {
      return { reachable: false, error: 'No A record' };
    }

    // Test connection to port 25
    const connected = await testConnection(addresses[0], 25);

    return {
      reachable: connected,
      ip: addresses[0],
      error: connected ? null : 'Connection refused'
    };
  } catch (error) {
    return {
      reachable: false,
      error: error.message
    };
  }
}

function testConnection(host, port, timeout = 5000) {
  return new Promise((resolve) => {
    const socket = new net.Socket();

    socket.setTimeout(timeout);

    socket.on('connect', () => {
      socket.destroy();
      resolve(true);
    });

    socket.on('timeout', () => {
      socket.destroy();
      resolve(false);
    });

    socket.on('error', () => {
      resolve(false);
    });

    socket.connect(port, host);
  });
}

Gestire il Fallback del Record A

Quando non esistono record MX, gli standard email (RFC 5321) specificano che il record A del dominio dovrebbe essere usato come fallback. Implementa questo fallback nella tua validazione:

async function getMailServers(domain) {
  // Try MX records first
  try {
    const mxRecords = await dns.resolveMx(domain);

    if (mxRecords.length > 0) {
      return {
        type: 'MX',
        servers: mxRecords.sort((a, b) => a.priority - b.priority)
      };
    }
  } catch (error) {
    if (error.code !== 'ENODATA') {
      throw error;
    }
  }

  // Fallback to A record
  try {
    const aRecords = await dns.resolve4(domain);

    if (aRecords.length > 0) {
      return {
        type: 'A_FALLBACK',
        servers: [{ exchange: domain, priority: 0 }],
        warning: 'Using A record fallback - no MX records found'
      };
    }
  } catch (error) {
    if (error.code !== 'ENODATA') {
      throw error;
    }
  }

  return {
    type: 'NONE',
    servers: [],
    error: 'No mail servers found for domain'
  };
}

Rilevare Record MX Null

RFC 7505 definisce record "null MX" che indicano esplicitamente che un dominio non accetta email. Questi record hanno una singola voce MX con priorità 0 e un hostname vuoto ("."):

function hasNullMx(mxRecords) {
  if (mxRecords.length === 1) {
    const record = mxRecords[0];
    if (record.priority === 0 &&
        (record.exchange === '.' || record.exchange === '')) {
      return true;
    }
  }
  return false;
}

async function validateDomainMx(domain) {
  const mxResult = await getMxRecords(domain);

  if (!mxResult.success) {
    return mxResult;
  }

  if (hasNullMx(mxResult.records)) {
    return {
      success: false,
      domain,
      error: 'NULL_MX',
      message: 'Domain explicitly does not accept email'
    };
  }

  return mxResult;
}

Caching delle Ricerche MX

Le ricerche DNS aggiungono latenza a ogni verifica. Implementa il caching per migliorare le prestazioni:

class MxCache {
  constructor(ttlMs = 3600000) { // 1 hour default TTL
    this.cache = new Map();
    this.ttl = ttlMs;
  }

  get(domain) {
    const entry = this.cache.get(domain.toLowerCase());

    if (!entry) return null;

    if (Date.now() > entry.expiry) {
      this.cache.delete(domain.toLowerCase());
      return null;
    }

    return entry.data;
  }

  set(domain, data) {
    this.cache.set(domain.toLowerCase(), {
      data,
      expiry: Date.now() + this.ttl
    });
  }

  // Respect DNS TTL values when available
  setWithTtl(domain, data, ttlSeconds) {
    const ttlMs = Math.min(ttlSeconds * 1000, this.ttl);
    this.cache.set(domain.toLowerCase(), {
      data,
      expiry: Date.now() + ttlMs
    });
  }
}

const mxCache = new MxCache();

async function getMxRecordsCached(domain) {
  const cached = mxCache.get(domain);

  if (cached) {
    return { ...cached, fromCache: true };
  }

  const result = await getMxRecords(domain);

  if (result.success) {
    mxCache.set(domain, result);
  }

  return { ...result, fromCache: false };
}

Pattern Comuni dei Record MX

Comprendere le configurazioni MX comuni aiuta a interpretare i risultati della validazione e identificare potenziali problemi.

Principali Provider Email

Riconoscere i pattern MX dei principali provider può aiutare a identificare indirizzi email gratuiti:

const knownProviders = {
  'google': [
    'gmail-smtp-in.l.google.com',
    'googlemail-smtp-in.l.google.com',
    'aspmx.l.google.com'
  ],
  'microsoft': [
    'outlook-com.olc.protection.outlook.com',
    'mail.protection.outlook.com'
  ],
  'yahoo': [
    'mta5.am0.yahoodns.net',
    'mta6.am0.yahoodns.net',
    'mta7.am0.yahoodns.net'
  ],
  'protonmail': [
    'mail.protonmail.ch',
    'mailsec.protonmail.ch'
  ]
};

function identifyEmailProvider(mxRecords) {
  const exchanges = mxRecords.map(r => r.exchange.toLowerCase());

  for (const [provider, patterns] of Object.entries(knownProviders)) {
    for (const pattern of patterns) {
      if (exchanges.some(ex => ex.includes(pattern.toLowerCase()))) {
        return provider;
      }
    }
  }

  return 'unknown';
}

Rilevamento Google Workspace

I domini Google Workspace (precedentemente G Suite) usano i server di posta di Google ma non sono account email gratuiti:

function isGoogleWorkspace(domain, mxRecords) {
  const isGoogleMx = mxRecords.some(r =>
    r.exchange.toLowerCase().includes('google') ||
    r.exchange.toLowerCase().includes('googlemail')
  );

  // Check if domain is not a known Google consumer domain
  const googleConsumerDomains = ['gmail.com', 'googlemail.com'];
  const isConsumerDomain = googleConsumerDomains.includes(domain.toLowerCase());

  return isGoogleMx && !isConsumerDomain;
}

Rilevamento Email Self-Hosted

I domini che ospitano la propria email spesso hanno record MX che puntano a sottodomini:

function isSelfHosted(domain, mxRecords) {
  const domainParts = domain.toLowerCase().split('.');
  const baseDomain = domainParts.slice(-2).join('.');

  return mxRecords.some(r => {
    const exchange = r.exchange.toLowerCase();
    return exchange.includes(baseDomain) &&
           !isKnownProvider(exchange);
  });
}

function isKnownProvider(exchange) {
  const providers = ['google', 'microsoft', 'yahoo', 'outlook', 'protonmail'];
  return providers.some(p => exchange.includes(p));
}

Validazione MX nelle Pipeline di Verifica Email

La validazione MX è un passaggio in un processo di verifica email completo. Comprendere il suo ruolo aiuta a costruire pipeline di verifica efficaci.

Ordine di Verifica

La validazione MX tipicamente avviene all'inizio della pipeline di verifica:

async function verifyEmail(email) {
  // 1. Syntax validation (fastest, no network)
  const syntaxResult = validateEmailSyntax(email);
  if (!syntaxResult.valid) {
    return { valid: false, reason: 'invalid_syntax', details: syntaxResult };
  }

  const domain = email.split('@')[1];

  // 2. MX record validation (fast DNS lookup)
  const mxResult = await validateMxRecords(domain);
  if (!mxResult.valid) {
    return { valid: false, reason: 'no_mx_records', details: mxResult };
  }

  // 3. Additional checks (disposable, role-based, etc.)
  const domainCheck = await checkDomainReputation(domain);
  if (domainCheck.isDisposable) {
    return { valid: true, risky: true, reason: 'disposable_domain' };
  }

  // 4. SMTP verification (slowest, most thorough)
  const smtpResult = await verifySmtp(email, mxResult.records);

  return {
    valid: smtpResult.exists,
    deliverable: smtpResult.deliverable,
    mxRecords: mxResult.records,
    provider: mxResult.provider
  };
}

Ricerche MX Parallele

Quando verifichi più email, parallelizza le ricerche MX per diversi domini:

async function verifyEmailsBatch(emails) {
  // Group emails by domain
  const emailsByDomain = {};

  for (const email of emails) {
    const domain = email.split('@')[1];
    if (!emailsByDomain[domain]) {
      emailsByDomain[domain] = [];
    }
    emailsByDomain[domain].push(email);
  }

  // Lookup MX records for all domains in parallel
  const domains = Object.keys(emailsByDomain);
  const mxResults = await Promise.all(
    domains.map(domain => getMxRecordsCached(domain))
  );

  // Map results back to domains
  const mxByDomain = {};
  domains.forEach((domain, index) => {
    mxByDomain[domain] = mxResults[index];
  });

  // Process emails with MX data
  const results = [];

  for (const email of emails) {
    const domain = email.split('@')[1];
    const mx = mxByDomain[domain];

    if (!mx.success) {
      results.push({ email, valid: false, reason: 'invalid_domain' });
      continue;
    }

    // Continue with SMTP verification using cached MX data
    const smtpResult = await verifySmtp(email, mx.records);
    results.push({ email, ...smtpResult });
  }

  return results;
}

Gestione degli Errori e Casi Limite

La validazione MX robusta gestisce varie condizioni di errore in modo elegante.

Gestione dei Timeout DNS

I problemi di rete possono causare blocchi delle ricerche DNS. Implementa la gestione dei timeout:

async function getMxRecordsWithTimeout(domain, timeoutMs = 10000) {
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('DNS_TIMEOUT')), timeoutMs);
  });

  try {
    const result = await Promise.race([
      getMxRecords(domain),
      timeoutPromise
    ]);
    return result;
  } catch (error) {
    if (error.message === 'DNS_TIMEOUT') {
      return {
        success: false,
        domain,
        error: 'TIMEOUT',
        message: 'DNS lookup timed out',
        retryable: true
      };
    }
    throw error;
  }
}

Gestione di Domini Non Validi

Gestisci i domini sintatticamente non validi prima di tentare ricerche DNS:

function isValidDomain(domain) {
  if (!domain || typeof domain !== 'string') {
    return false;
  }

  // Check length
  if (domain.length > 253) {
    return false;
  }

  // Check for valid characters and structure
  const domainRegex = /^(?!-)[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;

  if (!domainRegex.test(domain)) {
    return false;
  }

  // Check each label length
  const labels = domain.split('.');
  for (const label of labels) {
    if (label.length > 63) {
      return false;
    }
  }

  return true;
}

async function validateDomainMxSafe(domain) {
  if (!isValidDomain(domain)) {
    return {
      success: false,
      domain,
      error: 'INVALID_DOMAIN',
      message: 'Domain format is invalid'
    };
  }

  return await getMxRecordsWithTimeout(domain);
}

Gestire Fallimenti DNS Temporanei

I fallimenti DNS possono essere temporanei. Implementa logica di retry con backoff esponenziale:

async function getMxRecordsWithRetry(domain, maxRetries = 3) {
  const delays = [1000, 2000, 4000];

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const result = await getMxRecordsWithTimeout(domain);

    // Don't retry for definitive failures
    if (result.success ||
        result.error === 'NXDOMAIN' ||
        result.error === 'ENOTFOUND') {
      return result;
    }

    // Retry for temporary failures
    if (result.retryable && attempt < maxRetries - 1) {
      await sleep(delays[attempt]);
      continue;
    }

    return result;
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

Considerazioni sulla Sicurezza

La validazione MX introduce considerazioni sulla sicurezza che gli sviluppatori devono affrontare.

Prevenzione dello Spoofing DNS

Le query DNS standard non sono crittografate e vulnerabili allo spoofing. Considera l'uso di DNS over HTTPS (DoH) per applicazioni sensibili:

const https = require('https');

async function getMxRecordsDoH(domain) {
  const url = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(domain)}&type=MX`;

  return new Promise((resolve, reject) => {
    https.get(url, {
      headers: { 'Accept': 'application/dns-json' }
    }, (res) => {
      let data = '';

      res.on('data', chunk => data += chunk);

      res.on('end', () => {
        try {
          const response = JSON.parse(data);

          if (response.Status !== 0) {
            resolve({
              success: false,
              domain,
              error: 'DNS_ERROR',
              status: response.Status
            });
            return;
          }

          const records = (response.Answer || [])
            .filter(a => a.type === 15)
            .map(a => {
              const [priority, exchange] = a.data.split(' ');
              return {
                priority: parseInt(priority),
                exchange: exchange.replace(/\.$/, '')
              };
            })
            .sort((a, b) => a.priority - b.priority);

          resolve({
            success: records.length > 0,
            domain,
            records
          });
        } catch (error) {
          reject(error);
        }
      });
    }).on('error', reject);
  });
}

Rate Limiting delle Query DNS

Previeni abusi limitando la frequenza delle query DNS:

class DnsRateLimiter {
  constructor(maxQueriesPerSecond = 100) {
    this.tokens = maxQueriesPerSecond;
    this.maxTokens = maxQueriesPerSecond;
    this.lastRefill = Date.now();
  }

  async acquire() {
    this.refillTokens();

    if (this.tokens > 0) {
      this.tokens--;
      return true;
    }

    // Wait for token availability
    await sleep(1000 / this.maxTokens);
    return this.acquire();
  }

  refillTokens() {
    const now = Date.now();
    const elapsed = now - this.lastRefill;
    const tokensToAdd = (elapsed / 1000) * this.maxTokens;

    this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
    this.lastRefill = now;
  }
}

const dnsLimiter = new DnsRateLimiter(50);

async function getMxRecordsRateLimited(domain) {
  await dnsLimiter.acquire();
  return getMxRecords(domain);
}

Utilizzare BillionVerify per la Validazione MX

Sebbene implementare la validazione MX da soli fornisca valore educativo, i servizi professionali di verifica email come BillionVerify gestiscono la validazione MX come parte di una verifica email completa.

Vantaggi dell'Utilizzo di un'API di Verifica Email

Controlli Completi

L'API di verifica email di BillionVerify combina la validazione MX con controllo della sintassi, verifica SMTP, rilevamento di email temporanee e altro in una singola chiamata API. Questo elimina la necessità di mantenere più sistemi di validazione.

Infrastruttura Ottimizzata

I servizi professionali mantengono resolver DNS distribuiti globalmente, gestiscono il caching su larga scala e ottimizzano le prestazioni per milioni di verifiche.

Aggiornamenti Continui

Le configurazioni dei server di posta cambiano costantemente. I servizi di verifica email aggiornano continuamente i loro database di provider conosciuti, domini temporanei e pattern di server di posta.

Esempio di Integrazione API

async function verifyEmailWithBillionVerify(email) {
  const response = await fetch('https://api.billionverify.com/v1/verify', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.BV_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ email })
  });

  const result = await response.json();

  // MX information is included in the response
  console.log('MX Valid:', result.mx_found);
  console.log('Domain Valid:', result.domain_valid);
  console.log('Is Deliverable:', result.is_deliverable);

  return result;
}

Conclusione

La validazione dei record MX è un componente fondamentale della verifica email che conferma che un dominio può ricevere email prima di tentare controlli più intensivi in termini di risorse. Implementando una validazione MX appropriata, puoi filtrare rapidamente i domini non validi, ottimizzare le prestazioni di verifica e costruire applicazioni di gestione email più affidabili.

Punti chiave per la validazione dei record MX:

  1. Controlla sempre i record MX prima di tentare la verifica SMTP per risparmiare tempo e risorse
  2. Gestisci il fallback del record A secondo gli standard RFC per i domini senza record MX
  3. Implementa il caching per ridurre l'overhead delle ricerche DNS per verifiche ripetute
  4. Riconosci i pattern comuni per identificare provider email e potenziali rischi
  5. Gestisci gli errori in modo elegante con timeout, retry e messaggi di errore appropriati

Che tu stia costruendo un sistema di verifica email personalizzato o integrando con un servizio come BillionVerify, comprendere i record MX ti aiuta a costruire una migliore gestione email nelle tue applicazioni. Inizia a implementare la validazione MX oggi e fai il primo passo verso una verifica email completa.

I team che usano Instantly o Smartlead migliorano la deliverabilità pulendo le liste con BillionVerify prima di ogni campagna.

Confronta BillionVerify con ZeroBounce su precisione e velocità prima di scegliere un fornitore di verifica.

Leo
LeoFounder, BillionVerify
Approfondimenti sulla Verifica Email

Inizia a Verificare Oggi

Inizi a verificare email con BillionVerify oggi. Riceva 100 crediti gratuiti quando si registra - nessuna carta di credito richiesta. Si unisca a migliaia di aziende che migliorano il ROI del loro email marketing con una verifica email accurata.

Nessuna carta di credito richiesta · 100+ crediti gratuiti al giorno · Inizia in 30 secondi

99.9%
Precisione
Real-time
Velocità API
$0.00014
Per Email
100/day
Sempre Gratuito