Verify Endpoint

API reference for the MailCop email verification endpoint. Validate single email addresses in real-time.

Verify Endpoint

Validate a single email address and get instant results. Perfect for signup forms, CRM integrations, or any real-time validation needs.

Endpoint

POST https://api.mailcop.net/v1/verify

Authentication

Include your API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Request

Parameters

Parameter Type Required Description
email string Yes The email address to validate
validation_type string No mx or smtp. Defaults to mx
catch_all boolean No SMTP only. Also check whether the address’s domain accepts mail for any mailbox, returned as catch_all_domain. No extra credits. Defaults to false

Example request

curl -X POST https://api.mailcop.net/v1/verify \
  -H "Authorization: Bearer tm_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "validation_type": "mx"
  }'

Response

Success (200 OK)

{
  "email": "[email protected]",
  "status": "good",
  "validation_type": "mx",
  "role_account": false,
  "free_provider": false,
  "catch_all_domain": null,
  "result": {
    "domain": "example.com",
    "checks": { "filter": "pass", "disposable": "pass", "format": "pass", "mx": "pass", "smtp": "skipped" },
    "smtp": null
  },
  "credits_used": 1
}

Bad SMTP result

{
  "email": "[email protected]",
  "status": "bad",
  "validation_type": "smtp",
  "reason": "Mailbox does not exist",
  "reason_code": "mailbox_not_found",
  "role_account": false,
  "free_provider": false,
  "catch_all_domain": null,
  "result": {
    "domain": "club.org",
    "checks": { "filter": "pass", "disposable": "pass", "format": "pass", "mx": "pass", "smtp": "fail" },
    "smtp": { "code": 550, "enhanced_code": "5.1.1" }
  },
  "credits_used": 10
}

Response fields

Field Type Description
email string The email address that was validated
status string Result: good or bad
validation_type string Method used: mx or smtp
credits_used integer Number of credits charged
reason string Human-readable reason (only for bad status)
reason_code string Stable machine-readable reason, see below (only for bad status)
result.domain string Domain part of the address, null if the format is invalid
result.checks object pass, fail or skipped for each stage, in order: filter, disposable, format, mx, smtp. Stages after a failure are skipped
role_account boolean Local part is a role mailbox such as info@, support@, sales@
free_provider boolean Domain is a free mailbox provider such as Gmail or Yahoo
catch_all_domain boolean About the domain, not this address. true if the domain accepts mail for any mailbox, so a good SMTP result cannot confirm this mailbox exists: every address at the domain returns the same. false if the domain rejected a random mailbox, so good really means this mailbox exists. null when not requested, not a good SMTP result, or when the check was inconclusive (for example greylisted)
result.smtp object When the SMTP check failed with a server reply: code (e.g. 550) and enhanced_code (e.g. "5.1.1", null if the server sent none). null otherwise. The reply text is never returned
result.disposable boolean true when rejected as a disposable address

Status values

Status Meaning
good Valid email address, safe to send to
bad Invalid email, will likely bounce

Failure reasons

When status is bad, reason_code tells you why. Branch on reason_code; reason is display text and may change.

reason_code Description
invalid_format Email format is incorrect
no_mx_records Domain doesn’t exist or has no mail servers. A DNS timeout also lands here, so retry before treating it as permanent
mailbox_not_found Specific mailbox doesn’t exist (SMTP only). Only reported for mailbox-unknown replies, never for policy or reputation blocks
mailbox_full Recipient’s mailbox is full (SMTP only)
smtp_rejected Mail server refused the check, e.g. greylisting or a policy block (SMTP only). Says nothing about whether the mailbox exists
smtp_unreachable Could not connect to the mail server (SMTP only)
disposable_domain Known temporary email service
blocked_by_filter Matched one of your blocklist filters. reason holds your filter’s reason when set

Validation Types

MX Validation (default)

  • Cost: 1 credit
  • Speed: ~100ms
  • Checks: Email format, domain existence, MX records
{
  "email": "[email protected]",
  "validation_type": "mx"
}

SMTP Validation

  • Cost: 10 credits
  • Speed: ~1-3 seconds
  • Checks: Everything in MX, plus mailbox existence
  • Requires: Premium plan
{
  "email": "[email protected]",
  "validation_type": "smtp"
}

Error Responses

Missing email parameter (400)

{
  "error": "Email parameter is required"
}

Invalid validation type (422)

{
  "error": "Invalid validation_type. Must be 'mx' or 'smtp'",
  "valid_types": ["mx", "smtp"]
}

SMTP requires Premium (402)

{
  "error": "SMTP validation requires a Premium subscription",
  "current_plan": "starter"
}

Insufficient credits (402)

{
  "error": "Insufficient account credits"
}

Invalid API key (401)

{
  "error": "Invalid API key"
}

IP not allowed (403)

{
  "error": "IP address not allowed"
}

Rate limit exceeded (429)

{
  "error": "Rate limit exceeded"
}

Code Examples

JavaScript - Form validation

async function validateEmail(email) {
  const response = await fetch('https://api.mailcop.net/v1/verify', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ email })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error);
  }

  return response.json();
}

// Usage in a form
document.querySelector('form').addEventListener('submit', async (e) => {
  e.preventDefault();
  const email = document.querySelector('#email').value;
  
  try {
    const result = await validateEmail(email);
    if (result.status === 'good') {
      // Proceed with form submission
      e.target.submit();
    } else {
      alert('Please enter a valid email address');
    }
  } catch (error) {
    console.error('Validation error:', error);
  }
});

Python - Batch validation

import requests
import time

API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://api.mailcop.net/v1/verify'

def validate_email(email, validation_type='mx'):
    response = requests.post(
        BASE_URL,
        headers={'Authorization': f'Bearer {API_KEY}'},
        json={'email': email, 'validation_type': validation_type}
    )
    
    if response.status_code == 429:
        # Rate limited, wait and retry
        time.sleep(5)
        return validate_email(email, validation_type)
    
    return response.json()

# Validate a list of emails
emails = ['[email protected]', '[email protected]', '[email protected]']
results = []

for email in emails:
    result = validate_email(email)
    results.append(result)
    print(f"{email}: {result['status']}")

Ruby - Rails integration

class EmailValidationService
  API_URL = 'https://api.mailcop.net/v1/verify'
  
  def initialize(api_key)
    @api_key = api_key
  end
  
  def validate(email, validation_type: 'mx')
    response = HTTP.auth("Bearer #{@api_key}")
                   .post(API_URL, json: { 
                     email: email, 
                     validation_type: validation_type 
                   })
    
    JSON.parse(response.body)
  end
end

# Usage
validator = EmailValidationService.new(ENV['TRUEMAIL_API_KEY'])
result = validator.validate('[email protected]')

if result['status'] == 'good'
  # Email is valid
end

PHP - WordPress plugin example

function truemail_validate_email($email) {
    $api_key = get_option('truemail_api_key');
    
    $response = wp_remote_post('https://api.mailcop.net/v1/verify', [
        'headers' => [
            'Authorization' => 'Bearer ' . $api_key,
            'Content-Type' => 'application/json'
        ],
        'body' => json_encode(['email' => $email])
    ]);
    
    if (is_wp_error($response)) {
        return null;
    }
    
    return json_decode(wp_remote_retrieve_body($response), true);
}

// Hook into registration
add_filter('registration_errors', function($errors, $sanitized_user_login, $user_email) {
    $result = truemail_validate_email($user_email);
    
    if ($result && $result['status'] === 'bad') {
        $errors->add('invalid_email', 'Please enter a valid email address.');
    }
    
    return $errors;
}, 10, 3);

Best Practices

1. Use appropriate validation type

  • MX validation for high-volume, speed-critical scenarios
  • SMTP validation for important signups or campaigns

2. Handle errors gracefully

Always check for error responses and handle rate limits with retries.

3. Cache results

If validating the same email multiple times, cache the result to save credits.

4. Validate server-side

Never expose your API key in client-side code. Always validate from your backend.

5. Combine with filters

Use filters to block known bad addresses before they use credits.