A personalized email image is a picture made for one recipient — their name on an event ticket, their discount code on a coupon, their certificate — placed in the email like any other image. With Shareglint you design the image once as a template, then give each contact an image URL with their values: a signed URL that renders the first time a mail client fetches it, or a file rendered beforehand in a batch. Either way the email itself only holds <img src="…"> with that contact's URL, which your mailing tool fills in from a contact field.
Why a contact field, not a merge tag in the URL
The obvious idea — put *|FNAME|* into the image address — does not work with signed URLs. A signed URL (/i/{account}/{template}.png?name=Anna&s=…) carries an HMAC of its path and every field value, so nobody can change the name in the link and render on your quota. Your mailing tool fills merge tags at send time but cannot compute an HMAC, so the signature would not match the filled-in values.
The fix is one step earlier: compute each contact's full URL in a script, upload it as a contact field (CARD_URL), and use that field in the template. Mailchimp, for example, turns every audience field into a merge tag such as *|CARD_URL|*, usable in links and image URLs (Mailchimp merge tags); other tools have the same idea under another syntax.
<img src="*|CARD_URL|*" width="600" height="315"
alt="Your ticket for DevConf 2026, seat 14C" style="display:block;width:100%;max-width:600px;height:auto">
Method 1: signed URLs, rendered on first fetch
A signed URL is computed locally from your account id and signing secret — no request to the API, no quota until someone fetches it:
import { createHmac } from 'node:crypto';
// RFC 3986: encodeURIComponent leaves ! ' ( ) * alone.
const enc = (v) => encodeURIComponent(String(v))
.replace(/[!'()*]/g, (c) => '%' + c.charCodeAt(0).toString(16).toUpperCase());
export function signedImageUrl(template, fields, ext = 'png') {
const path = `/i/${process.env.ACCOUNT_ID}/${template}.${ext}`;
const query = Object.keys(fields).sort()
.map((name) => `${enc(name)}=${enc(fields[name])}`)
.join('&');
const s = createHmac('sha256', process.env.SIGNING_SECRET)
.update(`${path}?${query}`).digest('hex').slice(0, 32);
return `https://shareglint.com${path}?${query}&s=${s}`;
}
// One row per contact → CSV to import into your mailing tool.
for (const c of contacts) {
const url = signedImageUrl('event-ticket', { title: 'DevConf 2026', admit: c.name, seat: c.seat }, 'jpg');
console.log(`${c.email},${url}`);
}
The canonical string is the path, ? and every parameter except s, sorted by name and RFC 3986-encoded; s is the first 32 hex characters of HMAC-SHA256 with your signing secret. The docs describe it with examples in other languages; the account id is public, the signing secret is not.
What happens at send time: mail clients fetch the image soon after delivery, not when the email is opened. Gmail shows images automatically after scanning them, and senders cannot use image loading to learn about the reader's computer or location (Google) — the request comes from Google, not from the reader, and Apple Mail with Mail Privacy Protection "privately downloads remote content in the background when you receive a message" (Apple). So the first fetch — and the render — comes right after the send, for most recipients, whether they open the email or not. A render takes about a second; later fetches are redirects to the cached file.
Method 2: render everything before the send
If you would rather have every file in hand before you press send — to check them, or because your list is large and you want the renders out of the way — use a batch:
curl -X POST "https://shareglint.com/v1/batches" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "template": "event-ticket", "format": "jpeg", "csv_url": "https://example.com/attendees.csv" }'
Put the contact's email in an id column; each row's result comes back with that id and the image URL, so you can write the URLs back into the mailing tool as CARD_URL. Rows per batch by plan: Free 50, Starter 500, Pro 1,000, Scale 2,000, Business 5,000. A rendered image's URL stays valid for as long as we keep the file (365 days on paid plans, 30 on Free), which outlasts most campaigns — but an email opened after that would show a broken image, which a signed URL never does: it renders again.
Make the image work in email
- Format. Use JPEG or PNG. WebP is not supported by Outlook for Windows and is converted by Gmail (Can I email). A signed URL picks the format by its extension:
.jpgfor photos and gradients,.pngfor flat colours and sharp text. - Size. Email bodies are usually around 600 px wide. A 1200×630 template displayed at
width="600"is sharp on high-density screens. Raster files from signed URLs are twice the template size, so for a lighter file make a template at 600×315 and keep the samewidth. - Alt text. Many clients block images until the reader allows them, and screen readers read the
alt. Put the essential text — the seat, the code — inaltand in the email body too; never only in the image. - Dark mode. Some clients change colours in dark mode. A design with its own solid background (not transparent) keeps its look; built-in templates take
theme(darkorlight) if you want a dark version.
Cost
Each distinct image is one render; contacts with the same values share one file, and repeat fetches are free. With signed URLs, budget for nearly every recipient's image to be rendered, because the prefetching described above happens on delivery. For a 5,000-contact campaign that is about 5,000 renders: the Free plan's 100 a month is for testing, Starter is $9 for 2,000, Pro $29 for 10,000, and a one-off pack of 1,000 costs $8 (pricing). The Free plan also adds a watermark, which you do not want in a customer email.
What it does not do
- No live content. The same URL always returns the same image, and clients cache it: no countdowns that tick on each open, no prices that change after the send.
- No open tracking. Prefetching makes image requests a poor signal of opens anyway, and we do not report per-recipient fetches.
- No sending. We render images; your mailing tool sends the email.
- No native integration with mailing tools. Contact fields and CSV imports are the bridge; there is no Mailchimp or Kit app.
Ideas that fit
- Event tickets with name, seat and a QR code image you generate.
- Coupons with each customer's code — the code also in the text, so it can be copied.
- Course certificates linked from the completion email, as a PNG preview and a one-page PDF.
- "Your year in numbers" cards with three or four of the contact's own stats.
Templates for most of these are in the gallery; your own HTML and CSS works as well, with a free preview before you save it.