Customize Emails
Jetonomy's notification emails flow through a single pipeline: event → Notifier → subject/body resolution → filters → HTML render → email adapter. Every stage exposes a filter so you can adjust any aspect - subject line, body text, logo, accent color, headers, or the full rendered HTML - without replacing core template files.
Source references:
Notifier::send_email_notification():includes/notifications/class-notifier.php:926Notifier::render_email_template():includes/notifications/class-notifier.php:1093Notifier::locate_email_template():includes/notifications/class-notifier.php:1040- Architecture overview:
docs/developer/EMAILS.md
Notification types
Each type has its own subject + body template and its own web/email on/off toggle in user preferences.
| Type slug | When it fires |
|---|---|
reply_to_post |
Someone replies to a post you authored |
reply_to_reply |
Someone replies to a reply you authored |
mention |
@you appears in a post or reply |
accepted_answer |
Your reply was accepted as the answer on a Q&A post |
new_post_in_sub |
A new post appears in a space you are subscribed to |
vote_on_post |
Someone votes on your post |
moderation |
A moderator takes an action on your content |
join_request |
Someone asks to join a space you administer |
badge_earned |
You earn a badge (Pro) |
Placeholder tokens (admin templates)
Under Jetonomy → Settings → Email → Email Templates, admins can override the subject and body for each type. The following tokens are substituted before the filters fire:
| Token | Expands to |
|---|---|
{site} |
Site name from get_bloginfo('name') |
{user} |
Recipient's display name |
{message} |
The system-computed event message |
{type} |
The notification type slug |
{url} |
The deep-link URL for the event |
{post_title} |
Title of the related post (when available) |
{actor_display_name} |
Display name of the person who triggered the event |
{reply_excerpt} |
Excerpt from the related reply (when available) |
{space_title} |
Title of the related space (when available) |
Enriched tokens ({post_title}, {actor_display_name}, {reply_excerpt}, {space_title}) fall back to an empty string when the event has no related content, so existing templates never render a literal {token} string.
Developer filters
All filters live on Notifier::send_email_notification() or Notifier::render_email_template(). They run after admin template overrides and placeholder substitution.
jetonomy_email_subject
Filter the email subject line before sending.
Parameters
| Parameter | Type | Description |
|---|---|---|
$subject |
string |
Computed subject after placeholder substitution |
$type |
string |
Notification type slug |
$user |
WP_User |
Notification recipient |
Returns: string
Source: includes/notifications/class-notifier.php:988
add_filter( 'jetonomy_email_subject', function ( string $subject, string $type, \WP_User $user ): string {
if ( 'mention' === $type ) {
return '[Mention] ' . $user->display_name . ' - you were tagged in the community';
}
return $subject;
}, 10, 3 );
jetonomy_email_body
Filter the plain-text email body (the intro sentence shown above the CTA button). Placeholder substitution has already run.
Parameters
| Parameter | Type | Description |
|---|---|---|
$body |
string |
Rendered body text |
$type |
string |
Notification type slug |
$user |
WP_User |
Notification recipient |
Returns: string
Source: includes/notifications/class-notifier.php:998
add_filter( 'jetonomy_email_body', function ( string $body, string $type, \WP_User $user ): string {
// Append a reply-by-email instruction for reply notifications.
if ( in_array( $type, array( 'reply_to_post', 'reply_to_reply' ), true ) ) {
$body .= "\n\nTo reply, visit the community - reply-by-email is not supported.";
}
return $body;
}, 10, 3 );
jetonomy_email_headers
Filter the headers array passed to the email adapter for all notification emails.
Parameters
| Parameter | Type | Description |
|---|---|---|
$headers |
string[] |
Array of mail header strings (RFC 2822 format) |
$type |
string |
Notification type slug |
$user |
WP_User |
Notification recipient |
Returns: array
Source: includes/notifications/class-notifier.php:1017
The default headers already include List-Unsubscribe and List-Unsubscribe-Post (RFC 8058). Use this filter to append additional headers:
add_filter( 'jetonomy_email_headers', function ( array $headers, string $type, \WP_User $user ): array {
$headers[] = 'X-Community-Type: ' . $type;
$headers[] = 'X-Community-User: ' . $user->ID;
return $headers;
}, 10, 3 );
jetonomy_email_html
Filter the fully rendered HTML of the notification email immediately before it is passed to the email adapter.
Parameters
| Parameter | Type | Description |
|---|---|---|
$html |
string |
Full rendered HTML string |
$type |
string |
Notification type slug |
$user |
WP_User |
Notification recipient |
Returns: string
Source: includes/notifications/class-notifier.php:1208
add_filter( 'jetonomy_email_html', function ( string $html, string $type, \WP_User $user ): string {
// Inject a 1×1 tracking pixel before </body>.
$pixel_url = esc_url( add_query_arg( array(
'type' => $type,
'uid' => $user->ID,
), 'https://analytics.example.com/pixel.gif' ) );
$pixel = '<img src="' . $pixel_url . '" width="1" height="1" alt="" style="display:none">';
return str_replace( '</body>', $pixel . '</body>', $html );
}, 10, 3 );
jetonomy_email_accent_color
Filter the hex accent color used in notification email templates for the header bar and CTA button. Defaults to the accent_color setting, falling back to #3B82F6.
Parameters
| Parameter | Type | Description |
|---|---|---|
$color |
string |
Hex color string (e.g. '#3B82F6') |
$type |
string |
Notification type slug |
Returns: string
Source: includes/notifications/class-notifier.php:1109
// Use a red accent for moderation emails to signal urgency.
add_filter( 'jetonomy_email_accent_color', function ( string $color, string $type ): string {
return 'moderation' === $type ? '#DC2626' : $color;
}, 10, 2 );
jetonomy_email_logo_url
Filter the logo URL rendered in the email header. Return an empty string to fall back to the site name in plain text.
Parameters
| Parameter | Type | Description |
|---|---|---|
$url |
string |
Logo URL (empty string if none configured) |
$type |
string |
Notification type slug |
Returns: string
Source: includes/notifications/class-notifier.php:1119
add_filter( 'jetonomy_email_logo_url', function ( string $url, string $type ): string {
// Serve a CDN-hosted 2x logo regardless of the admin setting.
return 'https://cdn.example.com/email-logo@2x.png';
}, 10, 2 );
jetonomy_email_template_context
Filter the full context array passed into the email template renderer before the template file is included. Use this to inject additional variables that your custom template files (or a per-type template override) can read.
Parameters
| Parameter | Type | Description |
|---|---|---|
$ctx |
array |
Template variables array (see keys below) |
$type |
string |
Notification type slug |
$user |
WP_User |
Notification recipient |
Returns: array
Source: includes/notifications/class-notifier.php:1191
Standard keys in $ctx:
| Key | Type | Description |
|---|---|---|
type |
string |
Notification type slug |
type_label |
string |
Human-readable label (e.g. 'New Reply') |
site_name |
string |
HTML-escaped site name |
home_url |
string |
Escaped home URL |
community_url |
string |
URL for the event's deep link |
notif_url |
string |
URL to the notifications page |
unsub_url |
string |
Signed unsubscribe URL |
accent |
string |
Raw hex accent color |
logo_url |
string |
Escaped logo URL (empty string if none) |
cta_text |
string |
CTA button label |
cta_url |
string |
CTA button URL |
message |
string |
Rendered event message (raw; template escapes it) |
footer_text |
string |
Footer line from settings |
post_title |
string |
Related post title (empty if not applicable) |
actor_display_name |
string |
Name of the person who triggered the event |
reply_excerpt |
string |
Excerpt from the triggering reply |
space_title |
string |
Title of the related space |
user |
WP_User |
Recipient user object |
add_filter( 'jetonomy_email_template_context', function ( array $ctx, string $type, \WP_User $user ): array {
// Add the user's membership tier so the template can render a personalized footer.
$ctx['membership_tier'] = My_Membership::get_tier_label( $user->ID );
return $ctx;
}, 10, 3 );
jetonomy_email_template_path
Filter the resolved template file path before it is included. The lookup order before this filter is: child-theme override (yourtheme/jetonomy/emails/{type}.php) → plugin per-type (templates/emails/{type}.php) → child-theme base → plugin base (templates/emails/base.php).
Parameters
| Parameter | Type | Description |
|---|---|---|
$path |
string |
Absolute filesystem path to the template file |
$type |
string |
Notification type slug |
Returns: string
Source: includes/notifications/class-notifier.php:1076
// Point a specific type to a completely custom template.
add_filter( 'jetonomy_email_template_path', function ( string $path, string $type ): string {
if ( 'mention' === $type ) {
return MY_PLUGIN_DIR . 'templates/email-mention.php';
}
return $path;
}, 10, 2 );
Overriding a template file in a child theme
Without any PHP code, create a file at:
your-theme/jetonomy/emails/{type}.php
where {type} is the notification type slug with underscores replaced by hyphens - for example reply-to-post.php for the reply_to_post type. If no per-type file exists, base.php is used.
Inside the file you have access to all variables from the $ctx array above (extracted into local scope). Follow the structure of wp-content/plugins/jetonomy/templates/emails/base.php as your starting point.
Replacing the email adapter
To send Jetonomy emails through SMTP, SendGrid, Postmark, or any other provider, register a custom adapter. The adapter must implement \Jetonomy\Adapters\Email_Adapter (see includes/adapters/interface-email-adapter.php):
add_action( 'init', function () {
\Jetonomy\Adapters\Adapter_Registry::register_email(
'my-smtp',
new My_Plugin\SMTP_Adapter()
);
} );
// My_Plugin\SMTP_Adapter:
class SMTP_Adapter implements \Jetonomy\Adapters\Email_Adapter {
public function send(
string $to,
string $subject,
string $html,
string $plain,
array $headers
): bool {
return My_SMTP_Service::send( $to, $subject, $html, $headers );
}
}
See Adapters for the full adapter pattern documentation.
What's next
- Hooks Reference -
jetonomy_notification_created- listen for notification creation events to forward to mobile push or webhooks - Extend the REST API - expose notification data via a custom endpoint
- Adapters - swap the email transport entirely