Automating SureMails Setup in WordPress with wp-config and WP-CLI

Tech Articles | August 19, 2025 | Automation, Blog, Coding, Wordpress

Managing WordPress sites at scale means automating repetitive configuration tasks wherever possible. One such task is setting up your transactional email provider.

This article walks through a SureMails autosetup helper snippet that:

  • Automatically provisions a SureMails connection when the site is first loaded.
  • Stores sensitive API keys safely in wp-config.php.
  • Allows configuration via WP-CLI for remote deployment.
  • Ensures the setup runs only once (idempotent).
  • Cleans itself up after success (removes bootstrap snippet from Ninja Updater).

The part’s of this article that reference ninja updater are not really relevant to you, ninja updater is my utility plugin but it shows what can be done and how to hook this in so I decided to include them in the article to better frame how it works.

The Problem

Normally, setting up a SureMails connection requires logging into wp-admin, pasting in your API key, setting the “From” name and email, and making the connection the default.

For one site this isn’t a big deal. But if you manage dozens or hundreds of sites, doing this by hand quickly becomes unmanageable. Even worse when like me you can start 20 different sites for a project or tutorial series.

We need a way to:

  • Deploy sites automatically with a valid SureMails connection.
  • Keep API keys out of the database (store them in wp-config.php or environment).
  • Run the setup only once, and not overwrite changes later.

No Native Solution

Looking through code and asking on the Facebook group didn’t offer me any solutions to this there appears to be no current native solution to this so I needed to be able to create a solution that works for me I will be setting up in one of two ways depending on the service I am setting up on using constants either defined in wp-config or a snippet or WP-CLI

The approach

A lightweight autosetup helper reads configuration from wp-config.php (and/or WP-CLI flags), creates a SureMails connection, base64-encodes the API key if necessary, sets the connection as default, then marks itself done so it won’t run again.

Suremails auto example admin setup message

Configuration via wp-config.php

Add these constants to wp-config.php. The API key may be raw or already Base64—raw keys are encoded automatically.

efine( 'SUREMAILS_API_KEY', 'your-real-api-key' );          // required (raw or base64)
define( 'SUREMAILS_FROM_EMAIL', 'no-reply@example.com' );     // optional (defaults to admin_email)
define( 'SUREMAILS_FROM_NAME',  'Example Site' );             // optional (defaults to site title)
define( 'SUREMAILS_TYPE',       'EMAILIT' );                  // optional (e.g., EMAILIT, SMTP, SES)
define( 'SUREMAILS_TITLE',      'Emailit Connection' );       // optional (connection display name)
PHP

Heads up: The helper validates the key. If it isn’t valid Base64 or a sensible raw token (≥ 20 chars, no spaces), you’ll see a clear admin notice.

Suremails auto wpconfig setup

WP-CLI: set constants & run setup

Set constants (persistent)

Linux / macOS

wp config set SUREMAILS_API_KEY "your-real-api-key" --type=constant --anchor="/* That's all" --placement=before
wp config set SUREMAILS_FROM_EMAIL "no-reply@example.com" --type=constant
wp config set SUREMAILS_FROM_NAME  "Example Site"        --type=constant
wp config set SUREMAILS_TYPE       "SMTP"                --type=constant
wp config set SUREMAILS_TITLE      "My SMTP Connection"  --type=constant
PHP

Windows (PowerShell or cmd)

wp config set SUREMAILS_API_KEY "your-real-api-key" --type=constant --anchor="/* That's all" --placement=before
wp config set SUREMAILS_FROM_EMAIL "no-reply@example.com" --type=constant
wp config set SUREMAILS_FROM_NAME  "Example Site"        --type=constant
wp config set SUREMAILS_TYPE       "SMTP"                --type=constant
wp config set SUREMAILS_TITLE      "My SMTP Connection"  --type=constant
PHP

Run setup

Linux / macOS

wp suremails:setup \
  --from_email="no-reply@example.com" \
  --from_name="Example Site" \
  --type="SMTP" \
  --title="My SMTP Connection"
PHP

Windows (PowerShell use backticks

wp suremails:setup `
  --from_email="no-reply@example.com" `
  --from_name="Example Site" `
  --type="SMTP" `
  --title="My SMTP Connection"
PHP

Windows cmd.exe use a single line

wp suremails:setup --from_email="no-reply@example.com" --from_name="Example Site" --type="SMTP" --title="My SMTP Connection"
PHP

Note: CLI flags override constants for that one run.

Suremails auto wpcli setup message

Rotating API keys

Persistent (updates wp-config.php)

wp config set SUREMAILS_API_KEY "new-api-key" --type=constant --anchor="/* That's all" --placement=before
PHP

Database-only (quick hotfix)

wp suremails:rotate-key "new-api-key"
PHP

DB-only rotation updates the stored connection, but your wp-config.php constant is the long-term source of truth for the next setup run.

Reset & re-run

If you change constants and want to re-run setup, clear the run-once flag and remove the previous connection:

wp suremails:reset
PHP

What happens after success

  • A SureMails connection is created and set as the default.
  • The bootstrap snippet suremails_config.php is removed from Ninja Updater’s active snippets.
  • suremails_autosetup_done flag prevents re-running unless you reset.

Finding Connection Details

You can use a manually made connection and review the database option suremails_connections to find out what you should be calling your type in my examples its EMAILIT but these will vary between email providers.

Why this works

  • Secure by default: secrets live in wp-config.php, not in the DB.
  • Fully automatable: no wp-admin clicking required for new sites.
  • Idempotent & safe: run once, verified, then locked.
  • Flexible: configure via constants, CLI, or both.

The Snippet

I have again left in but commented out the ninja-updater stuff this is for reference you don’t need it but its useful for context.


<?php
/**
 * ============================================================================
 * SureMails Autosetup Helper
 * ============================================================================
 *
 * This drop-in handles automatic creation of a SureMails connection with
 * values pulled from wp-config.php constants OR WP-CLI flags. It is designed
 * to be idempotent, safe, and self-cleaning (removes the bootstrap snippet
 * `suremails_config.php` from Ninja Updater after a successful run).
 *
 * --------------------------------------------------------------------------
 * SUPPORTED CONSTANTS (set in wp-config.php)
 * --------------------------------------------------------------------------
 *
 * Required:
 *   SUREMAILS_API_KEY   = 'raw-or-base64-key'   // Raw or Base64 API key
 *
 * Optional:
 *   SUREMAILS_FROM_EMAIL = 'no-reply@example.com'
 *   SUREMAILS_FROM_NAME  = 'Example Site'
 *   SUREMAILS_TYPE       = 'EMAILIT'            // or SMTP, SES, etc.
 *   SUREMAILS_TITLE      = 'Emailit Connection' // display name in admin
 *
 * ============================================================================
 * SureMails Configuration (via wp-config.php constants)
 * ============================================================================
 *
 * Add the following to your wp-config.php to configure SureMails autosetup:
 *
 *   define( 'SUREMAILS_API_KEY', 'raw-or-base64-key' );
 *   define( 'SUREMAILS_FROM_EMAIL', 'no-reply@example.com' );
 *   define( 'SUREMAILS_FROM_NAME', 'Example Site' );
 *   define( 'SUREMAILS_TYPE', 'EMAILIT' );
 *   define( 'SUREMAILS_TITLE', 'Emailit Connection' );
 *
 * ============================================================================
 * WP-CLI INSTRUCTIONS
 * ============================================================================
 *
 * 1) Set your API key constant from CLI (persistent in wp-config.php):
 *
 *   ## Linux / macOS
 *   wp config set SUREMAILS_API_KEY "your-real-api-key" --type=constant --anchor="/* That's all" --placement=before
 *
 *   ## Windows PowerShell
 *   wp config set SUREMAILS_API_KEY "your-real-api-key" --type=constant --anchor="/* That's all" --placement=before
 *
 *   ## Windows cmd.exe
 *   wp config set SUREMAILS_API_KEY "your-real-api-key" --type=constant --anchor="/* That's all" --placement=before
 *
 *    - Use the raw key (not base64); the autosetup will encode it.
 *    - The `--type=constant` flag ensures a proper define() is written.
 *    - `--anchor="/* That's all"` with `--placement=before` ensures defines
 *      appear before WordPress’ stop-editing line.
 *
 * 2) Optionally set constants for email/name/type/title (persistent):
 *
 *   wp config set SUREMAILS_FROM_EMAIL "no-reply@example.com" --type=constant
 *   wp config set SUREMAILS_FROM_NAME  "Example Site"        --type=constant
 *   wp config set SUREMAILS_TYPE       "SMTP"                --type=constant
 *   wp config set SUREMAILS_TITLE      "My SMTP Connection"  --type=constant
 *
 * 3) Run setup:
 *
 *   ## Linux / macOS (bash/zsh)
 *   wp suremails:setup \
 *     --from_email="no-reply@example.com" \
 *     --from_name="Example Site" \
 *     --type="SMTP" \
 *     --title="My SMTP Connection"
 *
 *   ## Windows PowerShell (use backticks for line continuation)
 *   wp suremails:setup `
 *     --from_email="no-reply@example.com" `
 *     --from_name="Example Site" `
 *     --type="SMTP" `
 *     --title="My SMTP Connection"
 *
 *   ## Windows cmd.exe (single line only)
 *   wp suremails:setup --from_email="example@example.com" --from_name="SureMail" --type="EMAILIT" --title="Emailit Connection"
 *
 *   (CLI flags override constants for that run.)
 *
 * 4) Rotate the API key persistently (updates wp-config.php define):
 *
 *   wp config set SUREMAILS_API_KEY "new-api-key-here" --type=constant --anchor="/* That's all" --placement=before
 *
 * 5) Rotate the API key only in the database (leaves wp-config.php unchanged):
 *
 *   wp suremails:rotate-key "new-api-key-here"
 *
 *   (Useful for quick hotfixes, but the wp-config.php constant still takes priority on the next setup run.)
 *
 * 6) Reset the run-once flag so setup can run again with new constants:
 *
 *   wp suremails:reset
 *
 * --------------------------------------------------------------------------
 * AFTER SUCCESS
 * --------------------------------------------------------------------------
 *
 *   - A SureMails connection is created in the options table.
 *   - It is marked as the default connection.
 *   - `suremails_config.php` is removed from Ninja Updater’s active snippets.
 *   - Run-once flag prevents re-running unless you reset manually.
 *
 * ============================================================================
 */




/** -------------------- Validation helpers -------------------- **/

function suremails_is_base64($s): bool {
	if (!is_string($s) || $s === '') return false;
	$decoded = base64_decode($s, true);
	return $decoded !== false && base64_encode($decoded) === $s;
}

function suremails_looks_like_raw_key($s): bool {
	if (!is_string($s) || $s === '') return false;
	if (preg_match('/\s/', $s)) return false;
	if (strlen($s) < 20) return false;
	return (bool) preg_match('/^[A-Za-z0-9._\-:+=]{20,}$/', $s);
}

function suremails_validate_api_key(?string $key): array {
	$key = (string) $key;
	if ($key === '') {
		return ['ok' => false, 'is_base64' => false, 'reason' => 'empty'];
	}
	if (suremails_is_base64($key)) {
		return ['ok' => true, 'is_base64' => true, 'reason' => null];
	}
	if (suremails_looks_like_raw_key($key)) {
		return ['ok' => true, 'is_base64' => false, 'reason' => null];
	}
	return ['ok' => false, 'is_base64' => false, 'reason' => 'format'];
}

/** -------------------- Config resolver -------------------- **/

function suremails_resolve_config(array $cli_args = []): array {
	$api_key_raw = defined('SUREMAILS_API_KEY') ? SUREMAILS_API_KEY : '';

	$const_from_email = defined('SUREMAILS_FROM_EMAIL') ? SUREMAILS_FROM_EMAIL : '';
	$const_from_name  = defined('SUREMAILS_FROM_NAME')  ? SUREMAILS_FROM_NAME  : '';
	$const_type       = defined('SUREMAILS_TYPE')       ? SUREMAILS_TYPE       : '';
	$const_title      = defined('SUREMAILS_TITLE')      ? SUREMAILS_TITLE      : '';

	if (defined('WP_CLI') && WP_CLI) {
		if (!empty($cli_args['from_email'])) $const_from_email = $cli_args['from_email'];
		if (!empty($cli_args['from_name']))  $const_from_name  = $cli_args['from_name'];
		if (!empty($cli_args['type']))       $const_type       = $cli_args['type'];
		if (!empty($cli_args['title']))      $const_title      = $cli_args['title'];
	}

	$from_email = sanitize_email($const_from_email);
	if (empty($from_email)) {
		$from_email = sanitize_email(get_option('admin_email'));
	}
	$from_name = $const_from_name !== '' ? wp_strip_all_tags($const_from_name) : get_bloginfo('name', true);

	$type  = $const_type  !== '' ? strtoupper($const_type) : 'EMAILIT';
	$title = $const_title !== '' ? wp_strip_all_tags($const_title) : 'Emailit Connection';

	return [
		'api_key_raw' => (string) $api_key_raw,
		'from_email'  => (string) $from_email,
		'from_name'   => (string) $from_name,
		'type'        => (string) $type,
		'title'       => (string) $title,
	];
}

/** -------------------- Autosetup core -------------------- **/

function suremails_run_autosetup(array $cli_args = []): bool {
	$done_flag = 'suremails_autosetup_done';
	$lock_key  = 'suremails_autosetup_lock';

	if (get_option($done_flag) === 'yes') return true;

	$cfg = suremails_resolve_config($cli_args);
	$val = suremails_validate_api_key($cfg['api_key_raw']);
	if (!$val['ok']) return false;
	if (!is_email($cfg['from_email'])) return false;

	if (get_transient($lock_key)) return false;
	set_transient($lock_key, 1, 60);

	try {
		$option_name = 'suremails_connections';
		$settings = get_option($option_name);
		if (!is_array($settings)) {
			$settings = [
				'connections'             => [],
				'default_connection'      => null,
				'log_emails'              => 'yes',
				'delete_email_logs_after' => '30_days',
				'email_simulation'        => 'no',
			];
		}
		if (!isset($settings['connections']) || !is_array($settings['connections'])) {
			$settings['connections'] = [];
		}

		$api_key_b64 = $val['is_base64'] ? $cfg['api_key_raw'] : base64_encode($cfg['api_key_raw']);

		$id = md5(wp_json_encode([$cfg['type'], strtolower($cfg['from_email']), $cfg['title']]));

		$new_conn = [
			'connection_title' => $cfg['title'],
			'from_email'       => $cfg['from_email'],
			'force_from_email' => true,
			'from_name'        => $cfg['from_name'],
			'force_from_name'  => true,
			'priority'         => 20,
			'api_key'          => $api_key_b64,
			'id'               => $id,
			'type'             => $cfg['type'],
			'created_at'       => current_time('mysql'),
		];

		$settings['connections'][$id] = $new_conn;
		$settings['default_connection'] = [
			'type'             => $new_conn['type'],
			'email'            => $new_conn['from_email'],
			'id'               => $new_conn['id'],
			'connection_title' => $new_conn['connection_title'],
		];

		update_option($option_name, $settings, false);

		$verify = get_option($option_name);
		$ok = is_array($verify)
			&& isset($verify['connections'][$id])
			&& isset($verify['default_connection']['id'])
			&& $verify['default_connection']['id'] === $id;

		if ($ok) {
			update_option($done_flag, 'yes', false);

			// Remove suremails_config.php from Ninja Updater list
			/*$snippets = get_option('ninja_updater_selected_snippets');
			if (is_array($snippets) && !empty($snippets)) {
				$new_snippets = array_values(array_filter($snippets, fn($s) => $s !== 'suremails_config.php'));
				if ($new_snippets !== $snippets) {
					update_option('ninja_updater_selected_snippets', $new_snippets);
				}
			} /*
		}

		return (bool) $ok;

	} finally {
		delete_transient($lock_key);
	}
}

/** -------------------- Admin path -------------------- **/

add_action('admin_init', function () {
	if (!is_admin() || !current_user_can('manage_options')) return;
	suremails_run_autosetup();
});

add_action('admin_notices', function () {
	if (!current_user_can('manage_options')) return;
	if (get_option('suremails_autosetup_done') === 'yes') return;

	if (!defined('SUREMAILS_API_KEY') || SUREMAILS_API_KEY === '') {
		echo '<div class="notice notice-warning"><p><strong>SureMails:</strong> autosetup pending — define <code>SUREMAILS_API_KEY</code> in <code>wp-config.php</code> to complete setup.</p></div>';
	} else {
		$val = suremails_validate_api_key(SUREMAILS_API_KEY);
		if (!$val['ok']) {
			$why = $val['reason'] === 'empty'
				? 'The key is empty.'
				: 'The key is neither valid Base64 nor a typical raw token (≥20 chars, no spaces).';
			echo '<div class="notice notice-error is-dismissible"><p><strong>SureMails:</strong> '
			   . esc_html($why)
			   . ' Please update <code>SUREMAILS_API_KEY</code> in <code>wp-config.php</code>.</p></div>';
		}
	}
});

/** -------------------- WP-CLI commands -------------------- **/

if (defined('WP_CLI') && WP_CLI) {
	// Full setup
	WP_CLI::add_command('suremails:setup', function ($args, $assoc_args) {
		if (get_option('suremails_autosetup_done') === 'yes') {
			WP_CLI::success('SureMails autosetup already completed.');
			return;
		}
		if (!defined('SUREMAILS_API_KEY') || SUREMAILS_API_KEY === '') {
			WP_CLI::error('SUREMAILS_API_KEY is not defined in wp-config.php.');
		}

		$val = suremails_validate_api_key(SUREMAILS_API_KEY);
		if (!$val['ok']) {
			WP_CLI::error('SUREMAILS_API_KEY looks invalid: must be valid Base64 or a raw token (≥20 chars, no spaces).');
		}

		$ok = suremails_run_autosetup($assoc_args);

		if ($ok) {
			$settings = get_option('suremails_connections');
			$email = $settings['default_connection']['email'] ?? '(unknown)';
			$name  = $settings['connections'][ $settings['default_connection']['id'] ]['from_name'] ?? '(unknown)';
			$type  = $settings['default_connection']['type'] ?? '(unknown)';
			$title = $settings['default_connection']['connection_title'] ?? '(unknown)';

			WP_CLI::success(sprintf(
				'SureMails connection configured (type: %s, title: %s, from: %s, name: %s).',
				$type, $title, $email, $name
			));
		} else {
			WP_CLI::error('Autosetup did not complete. Check inputs, constants, and permissions.');
		}
	});

	// Rotate only the API key
	WP_CLI::add_command('suremails:rotate-key', function ($args) {
		if (empty($args[0])) {
			WP_CLI::error('Usage: wp suremails:rotate-key "new-api-key"');
		}
		$new_key = $args[0];

		$val = suremails_validate_api_key($new_key);
		if (!$val['ok']) {
			WP_CLI::error('Provided key looks invalid: must be valid Base64 or a raw token (≥20 chars, no spaces).');
		}
		$api_key_b64 = $val['is_base64'] ? $new_key : base64_encode($new_key);

		$settings = get_option('suremails_connections');
		if (!is_array($settings) || empty($settings['default_connection']['id'])) {
			WP_CLI::error('No existing SureMails default connection to update.');
		}
		$id = $settings['default_connection']['id'];
		if (isset($settings['connections'][$id])) {
			$settings['connections'][$id]['api_key'] = $api_key_b64;
			update_option('suremails_connections', $settings, false);
			WP_CLI::success('API key rotated successfully for connection: ' . $id);
		} else {
			WP_CLI::error('Default connection not found in connections list.');
		}
	});

	// Reset run-once flag AND remove the helper-created connection
	WP_CLI::add_command('suremails:reset', function () {
	// Clear the run-once flag first
	delete_option('suremails_autosetup_done');

	$settings = get_option('suremails_connections');
	if (!is_array($settings)) {
		WP_CLI::success('Run-once flag reset. No suremails_connections option found.');
		return;
	}

	// Recompute which connection this helper would have created (same id formula)
	$cfg = suremails_resolve_config(); // uses constants (no CLI overrides here)
	$type  = $cfg['type']  ?? 'EMAILIT';
	$title = $cfg['title'] ?? 'Emailit Connection';
	$from  = strtolower($cfg['from_email'] ?? '');

	$target_id = md5(wp_json_encode([$type, $from, $title]));

	$removed = false;

	// Remove that specific connection if present
	if (isset($settings['connections'][$target_id])) {
		unset($settings['connections'][$target_id]);
		$removed = true;

		// If that was the default, pick a new default (first remaining) or clear it
		$cur_default_id = $settings['default_connection']['id'] ?? null;
		if ($cur_default_id === $target_id) {
			$new_id = null;
			if (!empty($settings['connections'])) {
				$new_id = array_key_first($settings['connections']);
			}
			if ($new_id) {
				// Promote new default
				$new_conn = $settings['connections'][$new_id];
				$settings['default_connection'] = [
					'type'             => $new_conn['type'],
					'email'            => $new_conn['from_email'],
					'id'               => $new_conn['id'],
					'connection_title' => $new_conn['connection_title'],
				];
			} else {
				// No connections left; clear default
				unset($settings['default_connection']);
			}
		}
	}

	// If connections became empty, normalize the structure
	if (empty($settings['connections'])) {
		$settings['connections'] = [];
	}

	update_option('suremails_connections', $settings, false);

	if ($removed) {
		WP_CLI::success(sprintf(
			'Reset complete. Removed connection id %s and cleared the run-once flag.',
			$target_id
		));
	} else {
		WP_CLI::success('Reset complete. Run-once flag cleared. No matching connection to remove.');
	}
});

}
PHP

Watch the video that accompanies this article

Support the Author

buy me a coffee
Really Useful Plugin Logo
Wpvideobank temp
Appoligies for any spelling and grammer issue. As a dyslexic i need to rely on tools for this they like me are not perfect but I do try my best