A bit of Background:
I am a big fan of GridPane. I don’t currently offer any hosting and only really host a few sites of my own; I picked up one of their Developer LTDs a few years ago, the biggest WP purchase I’ve ever made, and have been getting my value out of it ever since. My sites are not uptime critical, but I am one of those people who want things to work and want the control I need and/or want at the time, and I still believe that GridPane now offers that.
Now, In terms of normal GridPane users, I am probably an anomaly. I don’t offer web hosting as a service but have used many of their feature set, Git, Canary, bundles, sever clone, site clone and even their API… I am not a regular user; I like to automate and deeply understand what I am using, and with GridPane, I feel I have a good understanding because of their bring-your-own-server model. I currently have about 10 in my account; only two are used, and the rest are just idling, ready for me to decide to use them.
Now, I am not a lucrative customer of GridPane. I donβt need flashy additional options, and I am pretty self-sufficient; with a great API, the GUI probably would only be used to access rarely used features, such as getting the user details for SFTP, but I knew reading about GridPane the stack and there dedication to GOOD hosting it was what I wanted.
Now, I recently commented on the Admin Bar Community about if anyone else finds GridPane’s API a bit frustrating; it has really low rate limits, and the methodology isn’t precisely slick; it requires far too many probes to get and do what you need, Patrick did comment on this and say they are looking to relaunch there API and has offered to show me there plans which I will certainly do, if I can help shape the way the API works this would be really good and as an avid fan of automation this to me seems like a no brainer (Plus I can see a nice tutorial series on automating with GridPane for automatic account creations, adding to Main WP, suspending and deleting on non-payment etc.)
The Problem:
On this thread, another user asked about Postmark integration within GridPane, and it got me thinking about something else Patrick said in that thread: “Most people in the WP ecosystem don’t really have the chops to build something from the ground up that even integrates a handful of simple API requests……….What it is that people really want is basically just a white label version of Kinsta/similar that they can slap their own logo on and call their own.”
See GridPane like InstaWP, another service I utilise at least until the API works a little better. Has no email delivery service, so you need to integrate with your provider to do this. You currently have two choices: set up your own SMTP / API within your WordPress site or utilise the GridPane API integration with Sendgrid.

It turns out I had already solved this (well, practically). Previously, I’ve used the useful FluentSMTP for SMTP delivery by a provider of my choice, and it works flawlessly in most cases except for two things.
1) it doesn’t work out of the box, so for tutorials, this means setting up SMTP delivery before I can use a site. In some cases, that can only last a few minutes; this just adds another unnecessary step for that work
2) I recently moved to a server provider that blocks standard SMTP ports for one of my actual live servers not by choice,e but it was what had to happen; this left me unable to utilise my usual transactional email delivery service
I also recently acquired an emailit account that offers API email delivery on a lifetime deal and also has very generous purchase credits that don’t expire. This let me look for other alternative methods. I hit upon the only reliable method, in my opinion,n beyond integration at the panel level, and this is an MU Plugin. It can’t be easily removed by mistake. It is there, and it loads as soon as the site does, so it is always there, set and waiting.
To fellow GridPane users, this isn’t new to you. We all have one already installed that allows the little automatically login to the server button to work within GridPane, and there are some good examples on the GridPane-Dev github

So, with my mind set up, I wrote an API interface which allows me to have an MU plugin that delivers via email and designed a delivery method for delivering the “payload” on-site setup.
In my personal opinion, it’s pretty elegant and simple.
1. As per the usual GridPane bundle emailit-deploy.zip gets added and activated from my personal repo
2. Emailit-deploy has only one job: it creates a mu-plugin file in the mu-directory, and then once it has done this, it deactivates and deletes itself much the same as my fork and improvement of WP-Tasks-After-Install does after it has done its modifications
It works great, and my sites with it installed in testing have had emails work perfectly to from the beginning. It works so well because emailit authorises sending domains, i.e. *@domain.com, and this means using a generic domain, I can have all emails delivered by that domain with the site title as the sender.
I have also added the ability to replace the hardcoded values within the mu-plugin with custom ones for each domain by using override values in WPcodeBox or functions.php, including a single one that allows me to turn off this MU plugin full stop if I want to
So, my next challenge was to see if I could get this to work with Postmark. After reviewing postmarks API for PHP and curl and comparing them to what I already had for emailit, I concluded that it was reasonably easy for me to do this based on the code I already had.
<?php
// Import the Postmark Client Class:
require_once('./vendor/autoload.php');
use Postmark\PostmarkClient;
$client = new PostmarkClient("");
$fromEmail = "[email protected]";
$toEmail = "[email protected]";
$subject = "Hello from Postmark";
$htmlBody = "<strong>Hello</strong> dear Postmark user.";
$textBody = "Hello dear Postmark user.";
$tag = "example-email-tag";
$trackOpens = true;
$trackLinks = "None";
$messageStream = "website-notifications";
// Send an email:
$sendResult = $client->sendEmail(
$fromEmail,
$toEmail,
$subject,
$htmlBody,
$textBody,
$tag,
$trackOpens,
NULL, // Reply To
NULL, // CC
NULL, // BCC
NULL, // Header array
NULL, // Attachment array
$trackLinks,
NULL, // Metadata array
$messageStream
);
?>
PHPSo, I signed up for a test account and had a working solution before Postmark even approved my account; I had to add my “domain” to Postmark. It is hard coded to use one of my approved domains, but it works right out of the box as intended emails are delivered to and from my email account.
<?php
/**
* Plugin Name: Gridpane - Postmark API Interface
* Plugin URI: https://reallyusefulplugins.com
* Description: Sends emails through the Postmark API Interface
* Version: 1.0
* Author: Reallyusefulplugins.com
* Author URI: https://reallyusefulplugins.com
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: postmark-api-interface
*
* To override the default settings, define the following constants in wp-config.php or a custom snippet:
*
* // Override the Server Token
* define('POSTMARK_SERVER_TOKEN', 'your-override-server-token');
*
* // Override the From Email
* define('POSTMARK_FROM_EMAIL', 'override@example.com');
*
* // Override the Message Stream
* define('POSTMARK_MESSAGE_STREAM', 'override-stream');
*/
// Hardcoded defaults
define('POSTMARK_DEFAULT_SERVER_TOKEN', ''); //replace
define('POSTMARK_DEFAULT_FROM_EMAIL', ''); //replace
define('POSTMARK_DEFAULT_MESSAGE_STREAM', ''); //replace
/**
* Intercept and send emails via the Postmark API.
*/
function rup_postmark_intercept_and_send_email_via_api($phpmailer) {
// Check if the override variable is set and true; if so, do nothing
if (defined('td_postmark_email_override') && td_email_override) {
error_log('Postmark API Override active; plugin execution skipped.');
return;
}
// Get the Server Token, allowing override via a constant or snippet
$server_token = defined('POSTMARK_SERVER_TOKEN') ? POSTMARK_SERVER_TOKEN : POSTMARK_DEFAULT_SERVER_TOKEN;
// Get the From Email, allowing override via constants or snippets
$from_email = defined('POSTMARK_FROM_EMAIL') ? POSTMARK_FROM_EMAIL : POSTMARK_DEFAULT_FROM_EMAIL;
// Get the Message Stream, allowing override via constants or snippets
$message_stream = defined('POSTMARK_MESSAGE_STREAM') ? POSTMARK_MESSAGE_STREAM : POSTMARK_DEFAULT_MESSAGE_STREAM;
// Extract email details from PHPMailer
$to_addresses = $phpmailer->getToAddresses();
$subject = $phpmailer->Subject ?: 'No Subject';
$html_body = $phpmailer->Body ?: '<strong>No content provided.</strong>';
// Validate 'to' addresses
$to = [];
foreach ($to_addresses as $address) {
if (filter_var($address[0], FILTER_VALIDATE_EMAIL)) {
$to[] = $address[0]; // Extract email address
}
}
if (empty($to)) {
error_log('Postmark API Error: No valid recipients');
return;
}
$to = implode(',', $to);
// Prepare headers
$headers = [
'Accept: application/json',
'Content-Type: application/json',
'X-Postmark-Server-Token: ' . $server_token,
];
// Prepare payload
$payload = json_encode([
'From' => $from_email,
'To' => $to,
'Subject' => $subject,
'HtmlBody' => $html_body,
'MessageStream' => $message_stream,
], JSON_UNESCAPED_UNICODE);
// Log payload for debugging
error_log('Postmark API Payload: ' . $payload);
// Send email via cURL
$url = 'https://api.postmarkapp.com/email';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
$response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// Log API response for debugging
error_log('Postmark API Response Code: ' . $response_code);
error_log('Postmark API Response: ' . $response);
if (curl_errno($ch)) {
error_log('Postmark API cURL Error: ' . curl_error($ch));
}
curl_close($ch);
// Prevent PHPMailer from sending the email
$phpmailer->ClearAllRecipients();
$phpmailer->ClearAttachments();
}
add_action('phpmailer_init', 'rup_postmark_intercept_and_send_email_via_api');
PHPThe above script works as intended now, as for how I deploy this as a MU plugin. I am not sure if I should share this, as it is good practice that plugins don’t self-delete and inject for security reasons. I already have one plugin publically that does its thing, makes the changes, and then deletes itself, as already mentioned in this article. I will let people decide on this. If people want this part of the plugin delivery, then ask, and I will write a separate blog post/video about it, as I don’t just use it for this, but the code is only about 70 lines, and it allows anything to be deployed to your mu directory if you upload it this could include a plugin you didn’t expect to upload it.
I can’t stress enough how careful you need to be with the code you get from the internet, even mine. I am not a security expert, and as such, there could be consequences for what I code. They work for me, but others may not. This snippet, if I publish it, could be installed by another plugin. Add the mu-plugin and delete it without you even knowing it was called if the sequences were correct.

I have to be cautious with some of this stuff for example, I haven’t released details on my ninja updater, which is a bundle installer, custom repo installer, plugin updater and snippet loading plugin because it is basically a GPL charter that can force any plugin to update from your own repo server; it runs snippets that enable features and plugins, allows me to deploy cloudflare rules in a single click once details are added, and it is probably the most useful utility, I’ve ever written you’ve seen it in my videos but it will remain mine because I fear it will end up on a GPL site offering updates to premium plugin providers I want to support, automatically removing there branding, there tags and updates from the GPL server.
The below video shows you a little about how the new Gridpane – Postmark API Interface works.
Thanks for watching