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
emailparameter - 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:
- Check that you’re including the
Authorizationheader - Verify the API key is correct (starts with
tm_live_) - 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:
- Check the API Overview for correct usage
- Review your API key settings
- Contact support at [email protected]