Error Handling

When something goes wrong with an API request, TrueMail returns an error response with details about what happened. This guide covers all error codes and how to handle them gracefully.

Error Response Format

All errors follow a consistent JSON format:

{
  "error": "Description of what went wrong"
}

Some errors include additional context:

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

HTTP Status Codes

400 Bad Request

The request is malformed or missing required parameters.

Common causes:

  • Missing required email parameter
  • Invalid JSON in request body
  • Malformed request headers

Example:

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

How to fix: Check your request parameters and ensure all required fields are included.


401 Unauthorized

Authentication failed. Your API key is missing, invalid, or revoked.

Example:

{
  "error": "Invalid API key"
}

How to fix:

  1. Check that you’re including the Authorization header
  2. Verify the API key is correct (starts with tm_live_)
  3. Check if the key was revoked in your dashboard

402 Payment Required

You don’t have enough credits for the requested operation, or you need to upgrade for the requested feature.

Examples:

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

How to fix:

  • Purchase more credits or a credit pack
  • Upgrade your plan for Premium features
  • Use a different validation type that’s available on your plan

403 Forbidden

The request is not allowed. Usually due to IP restrictions or feature limitations.

Examples:

{
  "error": "IP address not allowed"
}
{
  "error": "IP address filtering requires a premium plan"
}

How to fix:

  • Add your server’s IP to the API key’s allowed IPs
  • Upgrade to Premium for IP filtering features

404 Not Found

The requested resource doesn’t exist.

Example:

{
  "error": "Filter not found"
}

How to fix: Verify the resource ID is correct.


422 Unprocessable Entity

The request was understood but contains invalid data.

Examples:

{
  "error": "Invalid validation_type. Must be 'mx' or 'smtp'",
  "valid_types": ["mx", "smtp"]
}
{
  "error": "invalid email format"
}
{
  "error": "Value has already been taken"
}

How to fix: Check the validation rules and ensure your data matches the expected format.


429 Too Many Requests

You’ve exceeded the rate limit for your plan.

Example:

{
  "error": "Rate limit exceeded"
}

Rate limits:

  • Starter: 60 requests per 5 minutes
  • Premium: 300 requests per 5 minutes

How to fix:

  • Implement request throttling
  • Add delays between requests
  • Upgrade to Premium for higher limits

500 Internal Server Error

Something went wrong on our end. These are rare but can happen.

Example:

{
  "error": "Internal server error"
}

How to fix:

  • Retry the request after a short delay
  • If the problem persists, contact support

Handling Errors in Code

JavaScript

async function validateEmail(email) {
  try {
    const response = await fetch('https://api.truemail.app/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();
      
      switch (response.status) {
        case 401:
          throw new Error('Invalid API key. Please check your credentials.');
        case 402:
          throw new Error('Insufficient credits. Please top up your account.');
        case 429:
          // Retry after delay
          await sleep(5000);
          return validateEmail(email);
        case 500:
          throw new Error('Server error. Please try again later.');
        default:
          throw new Error(error.error || 'Unknown error occurred');
      }
    }

    return response.json();
  } catch (error) {
    console.error('Validation failed:', error.message);
    throw error;
  }
}

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

Python

import requests
import time
from enum import Enum

class TruemailError(Exception):
    def __init__(self, message, status_code=None):
        self.message = message
        self.status_code = status_code
        super().__init__(self.message)

class InsufficientCreditsError(TruemailError):
    pass

class RateLimitError(TruemailError):
    pass

class AuthenticationError(TruemailError):
    pass

def validate_email(email, retries=3):
    for attempt in range(retries):
        response = requests.post(
            'https://api.truemail.app/v1/verify',
            headers={'Authorization': 'Bearer YOUR_API_KEY'},
            json={'email': email}
        )
        
        if response.ok:
            return response.json()
        
        error_data = response.json()
        error_msg = error_data.get('error', 'Unknown error')
        
        if response.status_code == 401:
            raise AuthenticationError(error_msg, 401)
        
        elif response.status_code == 402:
            raise InsufficientCreditsError(error_msg, 402)
        
        elif response.status_code == 429:
            if attempt < retries - 1:
                wait_time = (attempt + 1) * 5  # Exponential backoff
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
                continue
            raise RateLimitError(error_msg, 429)
        
        elif response.status_code >= 500:
            if attempt < retries - 1:
                time.sleep(2)
                continue
            raise TruemailError(error_msg, response.status_code)
        
        else:
            raise TruemailError(error_msg, response.status_code)

# Usage
try:
    result = validate_email('[email protected]')
    print(f"Status: {result['status']}")
except InsufficientCreditsError:
    print("Please purchase more credits")
except RateLimitError:
    print("Too many requests. Please slow down.")
except AuthenticationError:
    print("Invalid API key")
except TruemailError as e:
    print(f"Error: {e.message}")

Ruby

class TruemailClient
  class Error < StandardError
    attr_reader :status_code
    
    def initialize(message, status_code = nil)
      @status_code = status_code
      super(message)
    end
  end
  
  class AuthenticationError < Error; end
  class InsufficientCreditsError < Error; end
  class RateLimitError < Error; end
  
  def initialize(api_key)
    @api_key = api_key
  end
  
  def validate(email, retries: 3)
    retries.times do |attempt|
      response = HTTP.auth("Bearer #{@api_key}")
                     .post('https://api.truemail.app/v1/verify', 
                           json: { email: email })
      
      return JSON.parse(response.body) if response.status.success?
      
      error = JSON.parse(response.body)['error']
      
      case response.status.code
      when 401
        raise AuthenticationError.new(error, 401)
      when 402
        raise InsufficientCreditsError.new(error, 402)
      when 429
        sleep((attempt + 1) * 5) if attempt < retries - 1
        next
      when 500..599
        sleep(2) if attempt < retries - 1
        next
      else
        raise Error.new(error, response.status.code)
      end
    end
    
    raise RateLimitError.new("Rate limit exceeded after retries", 429)
  end
end

# Usage
client = TruemailClient.new(ENV['TRUEMAIL_API_KEY'])

begin
  result = client.validate('[email protected]')
  puts "Status: #{result['status']}"
rescue TruemailClient::InsufficientCreditsError
  puts "Please purchase more credits"
rescue TruemailClient::RateLimitError
  puts "Rate limited. Please try again later."
rescue TruemailClient::AuthenticationError
  puts "Invalid API key"
rescue TruemailClient::Error => e
  puts "Error: #{e.message}"
end

PHP

class TruemailException extends Exception {
    protected $statusCode;
    
    public function __construct($message, $statusCode = 0) {
        $this->statusCode = $statusCode;
        parent::__construct($message, $statusCode);
    }
    
    public function getStatusCode() {
        return $this->statusCode;
    }
}

class InsufficientCreditsException extends TruemailException {}
class RateLimitException extends TruemailException {}
class AuthenticationException extends TruemailException {}

class TruemailClient {
    private $apiKey;
    
    public function __construct($apiKey) {
        $this->apiKey = $apiKey;
    }
    
    public function validate($email, $retries = 3) {
        for ($attempt = 0; $attempt < $retries; $attempt++) {
            $ch = curl_init('https://api.truemail.app/v1/verify');
            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_POST => true,
                CURLOPT_HTTPHEADER => [
                    'Authorization: Bearer ' . $this->apiKey,
                    'Content-Type: application/json'
                ],
                CURLOPT_POSTFIELDS => json_encode(['email' => $email])
            ]);
            
            $response = curl_exec($ch);
            $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            $data = json_decode($response, true);
            
            if ($statusCode === 200) {
                return $data;
            }
            
            $error = $data['error'] ?? 'Unknown error';
            
            switch ($statusCode) {
                case 401:
                    throw new AuthenticationException($error, 401);
                case 402:
                    throw new InsufficientCreditsException($error, 402);
                case 429:
                    if ($attempt < $retries - 1) {
                        sleep(($attempt + 1) * 5);
                        continue;
                    }
                    throw new RateLimitException($error, 429);
                default:
                    if ($statusCode >= 500 && $attempt < $retries - 1) {
                        sleep(2);
                        continue;
                    }
                    throw new TruemailException($error, $statusCode);
            }
        }
    }
}

// Usage
$client = new TruemailClient('YOUR_API_KEY');

try {
    $result = $client->validate('[email protected]');
    echo "Status: " . $result['status'];
} catch (InsufficientCreditsException $e) {
    echo "Please purchase more credits";
} catch (RateLimitException $e) {
    echo "Rate limited. Please try again later.";
} catch (AuthenticationException $e) {
    echo "Invalid API key";
} catch (TruemailException $e) {
    echo "Error: " . $e->getMessage();
}

Best Practices

1. Always check status codes

Don’t assume requests succeed. Check the HTTP status code before processing the response.

2. Implement retries with backoff

For rate limits (429) and server errors (5xx), implement exponential backoff:

const delays = [1000, 2000, 4000, 8000]; // milliseconds

for (let i = 0; i < delays.length; i++) {
  try {
    return await makeRequest();
  } catch (e) {
    if (e.status === 429 || e.status >= 500) {
      await sleep(delays[i]);
    } else {
      throw e;
    }
  }
}

3. Log errors for debugging

Keep logs of API errors to identify patterns and issues:

import logging

logger = logging.getLogger('truemail')

try:
    result = validate_email(email)
except TruemailError as e:
    logger.error(f"Validation failed: {e.message}", extra={
        'email': email,
        'status_code': e.status_code
    })

4. Handle insufficient credits gracefully

Check credits before bulk operations and alert users proactively:

const usage = await getUsage();
if (usage.credits.total < emailsToValidate) {
  showCreditPurchasePrompt();
  return;
}

5. Don’t expose errors to end users

Translate API errors into user-friendly messages:

function getUserMessage(error) {
  switch (error.status) {
    case 402:
      return "We couldn't validate this email. Please try again later.";
    case 429:
      return "Too many requests. Please wait a moment.";
    default:
      return "Something went wrong. Please try again.";
  }
}

Getting Help

If you encounter persistent errors or unexpected behavior:

  1. Check the API Overview for correct usage
  2. Review your API key settings
  3. Contact support at [email protected]