Club Mailer¶
Lets each WordPress user connect their own mail provider — Outlook / Microsoft 365 or Gmail /
Google Workspace — and send tagged wp_mail() messages as themselves, through the provider's own
API — not through the site's SMTP or transactional-mail account. A member connects one provider
at a time; connecting a second one replaces the first.
It is a companion to Club Player Manager, not part of it. It stores nothing about players, guardians or squads — only which mailbox each WordPress user has connected — and works whether or not the calling code is Club Player Manager itself.
What it does¶
- A member connects their own mailbox, from their WordPress profile page, in two clicks and an OAuth consent screen. No admin involvement per member.
- Other code tags a message for that member.
wp_mail()calls carrying anX-Club-Mailer-Send-As: <user id or email>header are diverted through that member's mailbox, sent from their address, and land in their own Sent Items. Everything else — core, WooCommerce, MailPoet, and every untaggedwp_mail()call — is left alone. - The site's admin registers an app per provider, once. Everything after that is self-service for members.
Requirements¶
- WordPress 6.5+, PHP 8.2+
- Pretty permalinks (Settings → Permalinks, anything but "Plain") — each OAuth redirect URI is a clean, query-free URL
- HTTPS — both Entra and Google Cloud Console reject
http://redirect URIs for a web app (barelocalhostis the one exception) - No Composer dependencies, and no build step
Setup¶
Settings → Club Mailer walks through registering a Microsoft Entra app (tenant, client ID,
client secret) and/or a Google Cloud OAuth client (client ID, client secret), and gives the exact
redirect URI each one needs pasted into it. A club only using one provider can leave the other's
fields blank — members are only offered a connect button for a provider the admin has configured.
Credentials can be stored on the settings screen, or pinned outside the database with
CLUB_MAILER_TENANT, CLUB_MAILER_CLIENT_ID, CLUB_MAILER_CLIENT_SECRET (Outlook) and
CLUB_MAILER_GOOGLE_CLIENT_ID, CLUB_MAILER_GOOGLE_CLIENT_SECRET (Gmail) constants in
wp-config.php — any of these overrides its stored value and the settings screen says so.
Once that is done, a member connects from Users → Profile → Send mail as yourself.
Admin¶
Settings → Club Mailer, gated on manage_options — deliberately not widened toward
cpm_manage_all the way most other satellite screens are, because the page stores OAuth client
secrets capable of sending mail as any member who connects a mailbox.
Using it from another plugin¶
wp_mail(
'recipient@example.com',
'Subject line',
'Message body',
array( 'X-Club-Mailer-Send-As: ' . $user_id )
);
Two functions exist only while this plugin is active, so function_exists() doubles as the "is
the mailer available?" check:
club_mailer_user_connected( $user_id )— whether that user has a connected mailbox, on whichever provider they connected.club_mailer_user_address( $user_id )— the address a tagged send will come from. Often not the user's WordPress profile email; returns''when not yet known rather than falling back to it. Check withfunction_exists()separately — an older copy of this plugin may lack it.
Data model¶
No custom tables. Per member: _club_mailer_active_provider (outlook or google), and for
whichever provider that names, _club_mailer_{provider}_refresh (the encrypted OAuth refresh
token) and _club_mailer_{provider}_address (the mailbox address, best-effort, backfilled on
the next token refresh if unknown) user meta. A member connected before this plugin supported more
than one provider has no _club_mailer_active_provider meta; club_mailer_user_connected() and
club_mailer_user_address() treat that as outlook, since that was the only provider then.
Site-wide: the club_mailer_settings option, holding one sub-array of credentials per provider.
Development¶
Everything runs from the repository root, where the shared dev tooling lives:
composer test # every plugin's suite
composer test:mailer # this plugin only
composer lint # every plugin's phpcs ruleset
composer lint:mailer # this plugin only
composer build -- club-mailer # dist/club-mailer/club-mailer-<version>.zip
Layout¶
club-mailer.php Bootstrap: constants, require order, hooks
uninstall.php Deletes the option and every member's meta
includes/
public-api.php club_mailer_user_connected()/user_address()
interface-club-mailer-provider.php The provider contract
class-club-mailer-outlook-provider.php Microsoft Graph: auth URL, token exchange,
send, mailbox address lookup
class-club-mailer-gmail-provider.php Gmail API: auth URL, token exchange, MIME send,
mailbox address lookup
class-club-mailer-settings.php Options: get() (merged over defaults, wp-config
constants win), save() — one sub-array per provider
class-club-mailer-connections.php Profile UI, connect/disconnect, each provider's OAuth
callback, the pre_wp_mail divert
admin/ The one settings screen, plus the orchestrator
templates/admin-settings.php
assets/css/ assets/js/
tests/Unit/ tests/Integration/ tests/Support/