Code examples

Plug in your key and the email variable. Every example calls the same endpoint and reads the same four fields.

The request

curl

curl -s https://api.verimail.io/v3/verify \
  -H "Authorization: Bearer $VERIMAIL_KEY" \
  -d "email=emma.wilson@acme-corp.com"

Node

const res = await fetch('https://api.verimail.io/v3/verify', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.VERIMAIL_KEY}` },
  body: new URLSearchParams({ email }),
});
const { verdict, reason, suggested_action } = await res.json();

Python

import os, requests

r = requests.post("https://api.verimail.io/v3/verify",
                  headers={"Authorization": f"Bearer {os.environ['VERIMAIL_KEY']}"},
                  data={"email": email}, timeout=30)
verdict = r.json()["verdict"]  # deliverable | undeliverable | risky | unknown

PHP

$ch = curl_init('https://api.verimail.io/v3/verify');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query(['email' => $email]),
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('VERIMAIL_KEY')],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);  // $data['verdict'], $data['reason']

Go

req, _ := http.NewRequest("POST", "https://api.verimail.io/v3/verify",
    strings.NewReader(url.Values{"email": {email}}.Encode()))
req.Header.Set("Authorization", "Bearer "+os.Getenv("VERIMAIL_KEY"))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
res, err := http.DefaultClient.Do(req)
if err != nil {
    return err
}
defer res.Body.Close()
var out struct {
    Verdict         string `json:"verdict"`
    Reason          string `json:"reason"`
    SuggestedAction string `json:"suggested_action"`
}
if err := json.NewDecoder(res.Body).Decode(&out); err != nil {
    return err
}

Handling the answer

Node

switch (data.verdict) {
  case 'deliverable':   return accept(email);
  case 'undeliverable': return reject(email, data.reason);  // e.g. "no_mail_server"
  case 'risky':                                              // catch-all, full mailbox, disposable
  case 'unknown':                                            // the server would not say; not billed
    return data.suggested_action === 'reject' ? reject(email, data.reason) : acceptAndConfirm(email);
}

Python

match data["verdict"]:
    case "deliverable":
        accept(email)
    case "undeliverable":
        reject(email, data["reason"])            # e.g. "no_mail_server"
    case "risky" | "unknown":                    # catch-all, full, disposable / the server would not say
        if data["suggested_action"] == "reject":
            reject(email, data["reason"])
        else:
            accept_and_confirm(email)

PHP

switch ($data['verdict']) {
    case 'deliverable':   accept($email); break;
    case 'undeliverable': reject($email, $data['reason']); break;   // e.g. "no_mail_server"
    case 'risky':                                                    // catch-all, full mailbox, disposable
    case 'unknown':                                                  // the server would not say; not billed
        $data['suggested_action'] === 'reject' ? reject($email, $data['reason']) : acceptAndConfirm($email);
}

Go

switch out.Verdict {
case "deliverable":
    accept(email)
case "undeliverable":
    reject(email, out.Reason) // e.g. "no_mail_server"
case "risky", "unknown": // catch-all, full mailbox, disposable / the server would not say (not billed)
    if out.SuggestedAction == "reject" {
        reject(email, out.Reason)
    } else {
        acceptAndConfirm(email)
    }
}

The reasoning behind the mapping is on handling results; every reason is in the result codes.