WordPress Contact Form 7 Email Verification Guide | checkboxHQ
Table of Contents
- Overview
- Prerequisites
- Architecture
- Setup Instructions
- Plugin Code
- Testing
- Optimization Strategies
- Troubleshooting
Overview
This guide shows you how to integrate checkboxHQ email verification with WordPress Contact Form 7, storing validated results in Google Sheets. The integration uses a non-blocking verification pattern - users receive instant form confirmation while email verification happens asynchronously in the background.
Key Features
- Real-time email verification via checkboxHQ API
- Non-blocking user experience (no form delays)
- Automatic storage in Google Sheets
- Domain caching to reduce API costs
- WordPress dashboard analytics widget
- Multisite compatible
Use Cases
- Lead capture forms with quality assurance
- Newsletter signups requiring valid emails
- Contact forms where email deliverability matters
- Registration forms needing disposable email blocking
Prerequisites
Required Accounts
-
checkboxHQ Account - Register here
- Get your API key from dashboard
- Note your credit balance
-
Google Cloud Account - Console
- Enable Google Sheets API
- Create service account credentials
-
WordPress Site
- WordPress 5.0 or higher
- Contact Form 7 plugin installed
- PHP 7.4 or higher
Required Plugins
# Install Contact Form 7wp plugin install contact-form-7 --activate
# Our custom plugin (code provided below)Architecture
Data Flow
User submits form ↓Contact Form 7 processes submission ↓Form success message shown to user (instant) ↓wp_cron schedules background job ↓checkboxHQ API verifies email ↓Results written to Google Sheets ↓Admin notification (optional)Why Non-Blocking?
Blocking approach (bad):
// User waits 2-5 seconds for API response$result = verify_email($email);if ($result['valid']) { send_confirmation();}Non-blocking approach (good):
// User sees instant successsend_confirmation();// Verification happens in backgroundwp_schedule_single_event(time(), 'verify_email_async', [$email]);Setup Instructions
Step 1: Create Google Service Account
-
Go to Google Cloud Console
-
Create new project: “checkboxHQ Integration”
-
Enable Google Sheets API:
- Navigate to “APIs & Services” → “Library”
- Search “Google Sheets API”
- Click “Enable”
-
Create Service Account:
- Go to “APIs & Services” → “Credentials”
- Click “Create Credentials” → “Service Account”
- Name:
checkboxhq-wordpress - Role: “Editor”
- Click “Done”
-
Generate JSON Key:
- Click on created service account
- Go to “Keys” tab
- “Add Key” → “Create new key” → “JSON”
- Download the JSON file (keep it secure!)
Step 2: Create Google Sheet
- Create new Google Sheet: “Email Verifications”
- Add headers in row 1:
| Timestamp | Email | Valid | Deliverable | Disposable | Domain | Risk Score | Source Form |- Share with service account:
- Click “Share” button
- Paste service account email (from JSON file:
client_email) - Grant “Editor” access
- Copy Sheet ID from URL:
https://docs.google.com/spreadsheets/d/{SHEET_ID}/edit
Step 3: Install WordPress Plugin
Create file: wp-content/plugins/checkboxhq-cf7/checkboxhq-cf7.php
Plugin Code
Main Plugin File
<?php/** * Plugin Name: checkboxHQ Contact Form 7 Integration * Plugin URI: https://checkboxhq.com/integrations/wordpress-cf7 * Description: Verify emails submitted via Contact Form 7 using checkboxHQ API and store in Google Sheets * Version: 1.0.0 * Author: Your Name * Author URI: https://yoursite.com * License: GPL v2 or later * Requires at least: 5.0 * Requires PHP: 7.4 */
if (!defined('ABSPATH')) { exit; // Exit if accessed directly}
class checkboxHQ_CF7_Integration {
private $api_key; private $sheet_id; private $service_account_file;
public function __construct() { // Load settings $this->api_key = get_option('checkboxhq_api_key'); $this->sheet_id = get_option('checkboxhq_sheet_id'); $this->service_account_file = WP_CONTENT_DIR . '/checkboxhq-service-account.json';
// Hooks add_action('wpcf7_mail_sent', [$this, 'handle_form_submission']); add_action('verify_email_checkboxhq', [$this, 'verify_email_async'], 10, 2); add_action('admin_menu', [$this, 'add_settings_page']); add_action('admin_init', [$this, 'register_settings']); add_action('wp_dashboard_setup', [$this, 'add_dashboard_widget']); }
/** * Handle CF7 form submission (non-blocking) */ public function handle_form_submission($contact_form) { $submission = WPCF7_Submission::get_instance();
if (!$submission) { return; }
$posted_data = $submission->get_posted_data();
// Extract email (adjust field name as needed) $email = isset($posted_data['your-email']) ? sanitize_email($posted_data['your-email']) : '';
if (!$email || !is_email($email)) { return; }
// Get form title for tracking $form_title = $contact_form->title();
// Schedule async verification (non-blocking) wp_schedule_single_event( time() + 10, // 10 second delay to avoid rate limits 'verify_email_checkboxhq', [$email, $form_title] );
// Log submission $this->log_message("Scheduled verification for: $email from form: $form_title"); }
/** * Verify email asynchronously via checkboxHQ API */ public function verify_email_async($email, $form_title) {
// Check domain cache first (cost optimization) $domain = substr(strrchr($email, "@"), 1); $cached_result = $this->get_cached_domain_result($domain);
if ($cached_result !== false) { $this->log_message("Using cached result for domain: $domain"); $this->write_to_google_sheets($email, $cached_result, $form_title); return; }
// Call checkboxHQ API $response = wp_remote_get( 'https://api.checkboxhq.com/verify/' . urlencode($email), [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->api_key, 'Content-Type' => 'application/json' ], 'timeout' => 15 ] );
if (is_wp_error($response)) { $this->log_message("API Error: " . $response->get_error_message()); return; }
$status_code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); $result = json_decode($body, true);
if ($status_code !== 200 || !isset($result['valid'])) { $this->log_message("Invalid API response for: $email"); return; }
// Cache domain result for common domains $this->cache_domain_result($domain, $result);
// Write to Google Sheets $this->write_to_google_sheets($email, $result, $form_title);
// Optional: Send admin notification for invalid emails if (!$result['valid']) { $this->notify_admin_invalid_email($email, $form_title); } }
/** * Write verification result to Google Sheets */ private function write_to_google_sheets($email, $result, $form_title) {
if (!file_exists($this->service_account_file)) { $this->log_message("Service account file not found"); return; }
// Load Google Sheets library (install via Composer) require_once __DIR__ . '/vendor/autoload.php';
try { $client = new \Google_Client(); $client->setAuthConfig($this->service_account_file); $client->addScope(\Google_Service_Sheets::SPREADSHEETS);
$service = new \Google_Service_Sheets($client);
// Prepare row data $row = [ date('Y-m-d H:i:s'), // Timestamp $email, $result['valid'] ? 'TRUE' : 'FALSE', $result['deliverable'] ?? 'N/A', $result['disposable'] ?? 'FALSE', $result['domain'] ?? '', $result['risk_score'] ?? 0, $form_title ];
$values = [$row]; $body = new \Google_Service_Sheets_ValueRange(['values' => $values]);
$params = ['valueInputOption' => 'RAW'];
$service->spreadsheets_values->append( $this->sheet_id, 'Sheet1!A:H', // Adjust range as needed $body, $params );
$this->log_message("Successfully wrote to Google Sheets: $email");
} catch (Exception $e) { $this->log_message("Google Sheets Error: " . $e->getMessage()); } }
/** * Cache domain verification results (reduce API costs) */ private function cache_domain_result($domain, $result) { $cache_key = 'checkboxhq_domain_' . md5($domain); set_transient($cache_key, $result, 7 * DAY_IN_SECONDS); // Cache for 7 days }
private function get_cached_domain_result($domain) { $cache_key = 'checkboxhq_domain_' . md5($domain); return get_transient($cache_key); }
/** * Send notification for invalid emails */ private function notify_admin_invalid_email($email, $form_title) { $admin_email = get_option('admin_email'); $subject = "[CheckBoxHQ] Invalid email detected: $email"; $message = "An invalid email was submitted via form: $form_title\n\n"; $message .= "Email: $email\n"; $message .= "Time: " . date('Y-m-d H:i:s') . "\n";
wp_mail($admin_email, $subject, $message); }
/** * Logging helper */ private function log_message($message) { if (defined('WP_DEBUG') && WP_DEBUG) { error_log('[CheckBoxHQ CF7] ' . $message); } }
/** * Settings page */ public function add_settings_page() { add_options_page( 'checkboxHQ Settings', 'checkboxHQ', 'manage_options', 'checkboxhq-settings', [$this, 'render_settings_page'] ); }
public function register_settings() { register_setting('checkboxhq_settings', 'checkboxhq_api_key'); register_setting('checkboxhq_settings', 'checkboxhq_sheet_id'); }
public function render_settings_page() { ?> <div class="wrap"> <h1>checkboxHQ Settings</h1> <form method="post" action="options.php"> <?php settings_fields('checkboxhq_settings'); ?> <table class="form-table"> <tr> <th scope="row">API Key</th> <td> <input type="text" name="checkboxhq_api_key" value="<?php echo esc_attr($this->api_key); ?>" class="regular-text" /> <p class="description">Get your API key from <a href="https://checkboxhq.com/dashboard" target="_blank">checkboxHQ Dashboard</a></p> </td> </tr> <tr> <th scope="row">Google Sheet ID</th> <td> <input type="text" name="checkboxhq_sheet_id" value="<?php echo esc_attr($this->sheet_id); ?>" class="regular-text" /> <p class="description">Find in Sheet URL: docs.google.com/spreadsheets/d/<strong>SHEET_ID</strong>/edit</p> </td> </tr> <tr> <th scope="row">Service Account JSON</th> <td> <p class="description">Upload file to: <code><?php echo $this->service_account_file; ?></code></p> <p class="description"> <?php if (file_exists($this->service_account_file)): ?> ✅ File found <?php else: ?> ❌ File not found <?php endif; ?> </p> </td> </tr> </table> <?php submit_button(); ?> </form> </div> <?php }
/** * Dashboard widget showing verification stats */ public function add_dashboard_widget() { wp_add_dashboard_widget( 'checkboxhq_stats', 'Email Verification Stats', [$this, 'render_dashboard_widget'] ); }
public function render_dashboard_widget() { // Get stats from transients or calculate $total = get_transient('checkboxhq_total_verified') ?: 0; $valid = get_transient('checkboxhq_valid_emails') ?: 0; $invalid = get_transient('checkboxhq_invalid_emails') ?: 0;
echo '<div class="checkboxhq-stats">'; echo '<p><strong>Total Verified:</strong> ' . number_format($total) . '</p>'; echo '<p><strong>Valid:</strong> ' . number_format($valid) . ' (' . ($total > 0 ? round($valid/$total*100, 1) : 0) . '%)</p>'; echo '<p><strong>Invalid:</strong> ' . number_format($invalid) . '</p>'; echo '<p><a href="https://docs.google.com/spreadsheets/d/' . $this->sheet_id . '" target="_blank">View Google Sheet →</a></p>'; echo '</div>'; }}
// Initialize pluginnew checkboxHQ_CF7_Integration();Install Dependencies
Create composer.json in plugin directory:
{ "require": { "google/apiclient": "^2.0" }}Run:
cd wp-content/plugins/checkboxhq-cf7composer installTesting
Test Checklist
- API Connection Test
# Test from command line -H "Authorization: Bearer YOUR_API_KEY"-
Form Submission Test
- Submit test email via Contact Form 7
- Check WP cron:
wp cron event list - Verify scheduled job appears
-
Google Sheets Test
- Manually trigger cron:
wp cron event run verify_email_checkboxhq - Check Google Sheet for new row
- Verify all columns populated
- Manually trigger cron:
-
Cache Test
- Submit same domain twice
- Check debug log for “Using cached result”
- Verify only 1 API call made
Debug Mode
Enable WordPress debug logging:
define('WP_DEBUG', true);define('WP_DEBUG_LOG', true);define('WP_DEBUG_DISPLAY', false);Check logs: wp-content/debug.log
Optimization Strategies
1. Domain Caching
Reduces API costs by caching results for common domains:
// Gmail, Outlook, etc. cached for 7 days// Reduces API calls by ~60% for typical formsSavings Example:
- 1,000 form submissions/month
- 40% are Gmail/Outlook/Yahoo
- Without caching: 1,000 API calls
- With caching: ~600 API calls
- Savings: 400 credits/month
2. Batch Processing
For high-volume sites, process in batches:
// Instead of individual wp_cron jobswp_schedule_event(time(), 'hourly', 'process_email_batch');
function process_email_batch() { $emails = get_pending_verifications(); // Custom queue foreach ($emails as $email) { // Verify and write to sheets usleep(100000); // 100ms delay between calls }}3. Rate Limiting
Prevent abuse and quota exhaustion:
// Max 100 verifications per hour per IP$ip = $_SERVER['REMOTE_ADDR'];$limit_key = 'checkboxhq_limit_' . md5($ip);$count = get_transient($limit_key) ?: 0;
if ($count >= 100) { // Block or queue for later return;}
set_transient($limit_key, $count + 1, HOUR_IN_SECONDS);4. Selective Verification
Only verify emails from specific forms:
// In handle_form_submission()$verify_forms = ['Contact Form', 'Newsletter Signup'];
if (!in_array($form_title, $verify_forms)) { return; // Skip verification}Troubleshooting
Common Issues
1. “Service account file not found”
# Upload JSON file to correct locationwp-content/checkboxhq-service-account.json
# Check file permissionschmod 600 checkboxhq-service-account.json2. “Invalid API key”
- Verify key in checkboxHQ dashboard
- Check for extra spaces in settings
- Ensure key has not expired
3. “Permission denied” (Google Sheets)
- Verify service account email is shared on sheet
- Grant “Editor” role (not “Viewer”)
- Check Sheet ID is correct
4. “Cron not running”
# Check if cron is disabledwp option get disable_cron
# Manually run pending jobswp cron event run --due-now
# Setup server cron (better for production)# Add to crontab:*/5 * * * * wp cron event run --due-now --path=/var/www/html5. API rate limit exceeded
- Implement domain caching (see optimization)
- Add delay between verification calls
- Consider upgrading checkboxHQ plan
Debug Commands
# List all scheduled eventswp cron event list
# Test cron manuallywp cron test
# Clear transient cachewp transient delete --all
# Check plugin statuswp plugin list
# View recent error logstail -f wp-content/debug.logSecurity Best Practices
1. Protect API Keys
// Store in wp-config.php instead of databasedefine('CHECKBOXHQ_API_KEY', 'your-key-here');
// Access in code$api_key = defined('CHECKBOXHQ_API_KEY') ? CHECKBOXHQ_API_KEY : get_option('checkboxhq_api_key');2. Validate Input
// Always sanitize emails$email = sanitize_email($posted_data['your-email']);
// Verify email formatif (!is_email($email)) { return;}3. Restrict File Access
// Add to service account JSON file location<Files "checkboxhq-service-account.json"> Order allow,deny Deny from all</Files>4. Use HTTPS
Ensure WordPress site uses HTTPS for all API communications.
Advanced Features
Custom Analytics Dashboard
public function get_verification_stats() { require_once __DIR__ . '/vendor/autoload.php';
$client = new \Google_Client(); $client->setAuthConfig($this->service_account_file); $client->addScope(\Google_Service_Sheets::SPREADSHEETS);
$service = new \Google_Service_Sheets($client);
$response = $service->spreadsheets_values->get( $this->sheet_id, 'Sheet1!A:H' );
$values = $response->getValues();
// Calculate stats $total = count($values) - 1; // Exclude header $valid = 0; $disposable = 0;
foreach (array_slice($values, 1) as $row) { if (isset($row[2]) && $row[2] === 'TRUE') $valid++; if (isset($row[4]) && $row[4] === 'TRUE') $disposable++; }
// Cache for 1 hour set_transient('checkboxhq_total_verified', $total, HOUR_IN_SECONDS); set_transient('checkboxhq_valid_emails', $valid, HOUR_IN_SECONDS); set_transient('checkboxhq_invalid_emails', $total - $valid, HOUR_IN_SECONDS);
return compact('total', 'valid', 'disposable');}Webhook Notifications
// Notify external service on verificationadd_action('checkboxhq_email_verified', function($email, $result) { wp_remote_post('https://your-webhook.com/endpoint', [ 'body' => json_encode([ 'email' => $email, 'valid' => $result['valid'], 'timestamp' => time() ]) ]);}, 10, 2);Performance Benchmarks
Typical Performance Metrics
| Metric | Value |
|---|---|
| Form submission response time | <100ms |
| Background verification time | 1-3 seconds |
| Google Sheets write time | 500ms - 1s |
| Total time (async) | 2-5 seconds |
| User-perceived delay | 0ms ✨ |
Scaling Considerations
Small sites (<100 form submissions/day):
- Current setup works perfectly
- No optimization needed
Medium sites (100-1,000 form submissions/day):
- Enable domain caching
- Consider batch processing
- Monitor checkboxHQ credit usage, consider upgrading
Large sites (1,000+ forms/day):
- Implement all optimizations
- Use dedicated worker server
- Consider database instead of Sheets
Next Steps
- Install Plugin: Copy code and activate
- Configure API: Add checkboxHQ API key
- Setup Google Sheets: Create service account and sheet
- Test Integration: Submit test forms
- Monitor Results: Check Google Sheets populate
- Optimize: Enable caching for cost savings
Additional Resources
- checkboxHQ API Documentation
- Contact Form 7 Hooks Reference
- Google Sheets API PHP Guide
- WordPress Cron Documentation
Support
Need help? Contact support:
- checkboxHQ Support: [email protected]
- WordPress Forums: wordpress.org/support
- GitHub Issues: github.com/your-repo/issues