Today I woke up to a post on the Ghost forum that piqued my interest:

Can you insert a member's ID into emails that are sent by Ghost? Should be easy, right?
Most people using Ghost's newsletter feature have probably used an email card. That's the nifty little tool that lets you add email-specific content that won't show up when the post is rendered in a browser:

This email card introduces the concept of email personalization. You can address your subscriber by their first name – and if that's not available, it falls back to saying "Hey there". Cool!
When I read the post from the Ghost forum, I wanted to link to some sort of documentation that Ghost has published. Yet, there is none. The email personalization is kind of a black hole.
There are a few old threads on the forum, each diving into one personalization option or another – or "merge tags", as they're sometimes called. But there's no comprehensive list.
So, uhh...here you go. A little bit of a deep dive into Ghost's email personalization.
How Does Ghost's Email Personalization Work?
When you're writing in an email card, you use simple curly braces with certain keywords:
{property_name}
For each of these, you can also add a fallback value, in case the property you're trying to display isn't available (e.g., the member hasn't added a name):
{property_name, "fallback text"}
Behind the scenes, Ghost converts these and merges them with actual member data..
The entire code responsible for this is in the EmailRenderer.js
:
And these are the personalizations that are available:
Personal Information
{first_name}
- Just the first name (extracts from full name){name}
- Full name{email}
- Email address
Member Status & Subscription
{status}
- Shows: free, paid, complimentary, or trialing{status_text}
- Human-readable status with dates like "Your subscription will renew on August 15, 2025"{created_at}
- When they became a member
Account Management
{unsubscribe_url}
- Unsubscribe link{manage_account_url}
- Link to account portal
Technical Helpers
{key}
- Validation key for secure operations{name_class}
- CSS helper (returns "hidden" if no name provided)
Getting The Member ID Into An Email
There's one gotcha. If you've read the EmailRenderer.js
, you might have spotted that there's also a uuid
property in there. For the initial question on the Ghost forum that started this quest for me, this would have been all they needed.
But...it's not that easy. The EmailRenderer.js
has this comment:
// We don't allow the usage of the %%{uuid}%% replacement in the email body
// (only in links and special cases)
html = html.replace(/%%{uuid}%%/g, '{uuid}');
Why? Security. Member UUIDs
are sensitive identifiers that Ghost only uses internally for tracking links and unsubscribe URLs.
Quick update: Cathy correctly pointed out that the uuid
is actually exposed in Ghost's comments. So uhh...make of that what you want 🙃
However, if you try to use {uuid}
in your email content, it'll just show up as literal text {uuid}
.
Bummer.
And while we're at it...
Email Cards Only
Yes, personalizations only work in email cards. It kinda makes sense. But it's also quite a big limitation. You can't use them in HTML cards to render something like <img>
tags.
And well, email cards themselves cannot render images or HTML at all. They are just...text. Again, this makes sense, since emails should be able to render in both HTML and plain text.
So, that defeats the solution the original poster from the forum set out to implement.
What you can do, however, is adding links in there. Most email clients would make these clickable. This way, you could generate unique links that lead to some sort of dashboard.
Option 1: Use Email Address
This is probably your best bet because email addresses are unique per member. They're always available and stay up to date. Inside an email card you could add:
Your personalized content:
https://example.com/content?member={email}
Option 2: Use the Validation Key as a Unique Identifier
While you can't reverse the key to get the UUID
, you can use it as a unique identifier on its own. Each member gets a unique key that's consistent. You could store a mapping of key -> member preferences
on your custom server, though you'd first need to calculate all the keys.
Your personalized content:
https://example.com/content?key={key}
Option 3: Get Creative With Multiple Parameters
You could even combine multiple member attributes for more sophisticated personalization:
Your personalized content:
https://example.com/content?member={email}&status={status}&joined={created_at}
What Doesn't Work
Here's what I tried that doesn't work, so you don't have to:
❌ HTML Cards
<!-- This stays as literal text -->
<img src="https://example.com/content?user={email}">
<p>Hello {first_name}</p>
❌ Pasted Images
Images (and image URLs) pasted directly into Ghost become static HTML and can't use personalizations.
❌ Using %%{property}%% Directly
Even if you try to use Ghost's internal %%{property}%%
format, it won't work in anything except email cards.
The bottom line: Only email cards process personalizations. Everything else treats them as literal text 🙃
I came to realize that Ghost's email personalization system is more limited than you might expect, but also more powerful within those limits. The email-cards-only restriction is a significant gotcha, but hey...developers love to be creative with constraints, right? 😄

About Jannis Fedoruk-Betschki
I'm the founder of Magic Pages, providing managed Ghost hosting that makes it easy to focus on your content instead of technical details.