USE CASE
EMAIL

Images That Survive Every Email Client

Outlook strips your CSS. Gmail ignores your media queries. But every email client renders images. So render your content as an image.

OUTPUT PREVIEW
SCALE 1:1
From: Acme Fitness|Subject: Your weekly stats are in

Hey Jordan, here's your weekly progress:

Jordan's DashboardThis Week
2,847Steps Today
12Day Streak
89%Goal Hit Rate

Keep it up! You're on a 12-day streak.

Template + variables = image. That's the whole flow.RENDERED
SECTION 01

Email CSS Is Broken

You want personalized stats or a progress bar in your email. Outlook doesn't support flexbox. Gmail strips your media queries. Yahoo wraps your columns. What looked right in your editor is broken in every inbox.

The standard fix is nested tables with inline styles. It barely works, it's painful to maintain, and you still can't do real visual personalization. Just "Hi {name}" and hope for the best.

SECTION 02

Render It as an Image

Build your personalized content as a JSX template. Pass each recipient's data as variables. Mint a signed URL per user with the batch endpoint (up to 25 per request).

Drop the URL in an <img> tag. The image renders on first open, caches after that, and looks identical in every email client. No tables, no CSS hacks, no cross-client testing.

SECTION 03

Example

FIG. 02
email-personalization.ts
email-personalization.ts
Shell
1// Mint personalized image URLs for each recipient2const recipients = [3  { name: "Jordan", steps: "2,847", streak: "12", goalRate: "89%" },4  { name: "Alex", steps: "4,102", streak: "28", goalRate: "94%" },5];67const urls = await fetch("https://api.htmlpix.com/v1/urls", {8  method: "POST",9  headers: {10    Authorization: `Bearer ${process.env.HTMLPIX_KEY}`,11    "Content-Type": "application/json",12  },13  body: JSON.stringify({14    items: recipients.map((r) => ({15      templateId: EMAIL_STATS_TEMPLATE_ID,16      variables: {17        userName: r.name,18        stat1Value: r.steps,19        stat1Label: "Steps Today",20        stat2Value: r.streak,21        stat2Label: "Day Streak",22        stat3Value: r.goalRate,23        stat3Label: "Goal Hit Rate",24      },25      width: 600,26      height: 300,27    })),28  }),29});3031// Each URL is unique per recipient32// Embed: <img src="https://image.htmlpix.com/v1/image?..." />
Copy, paste, run. That's it.READY TO RUN
SECTION 04

Integration Snippets

lib/emailImages.ts
TypeScript
interface Recipient {
  email: string;
  name: string;
  stats: { steps: string; streak: string; goalRate: string };
}

export async function mintEmailImages(recipients: Recipient[]) {
  const res = await fetch("https://api.htmlpix.com/v1/urls", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.HTMLPIX_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      items: recipients.map((r) => ({
        templateId: process.env.EMAIL_STATS_TEMPLATE_ID,
        variables: {
          userName: r.name,
          stat1Value: r.stats.steps,
          stat1Label: "Steps Today",
          stat2Value: r.stats.streak,
          stat2Label: "Day Streak",
          stat3Value: r.stats.goalRate,
          stat3Label: "Goal Hit Rate",
        },
        width: 600,
        height: 300,
      })),
    }),
  });

  const { urls } = await res.json();
  return recipients.map((r, i) => ({
    email: r.email,
    imageUrl: urls[i].url,
  }));
}
SECTION 05

Time & Cost Savings

Without HTMLPix

Nested tables with inline CSS. Hours of cross-client testing per campaign. Visual personalization basically impossible.

With HTMLPix

Build template once, mint a URL per recipient. Images look the same everywhere. Starts at $8/month.

Estimated Savings
No cross-client testing
SECTION 06

Why HTMLPix

01

Same Image, Every Client

An image tag works the same in Outlook 2016, Gmail on Android, Apple Mail, and Yahoo. No rendering differences.

02

Actual Personalization

Each recipient gets their own stats, progress bar, or dashboard. Not a merge tag with their name. A unique image with their data.

03

Batch Minting

POST /v1/urls takes up to 25 items per request. Mint a unique image URL for each recipient in your send list.

04

No Alt Text Trap

Some clients block images by default. Keep important text outside the image and use the image for the visual content that CSS can't handle.

SECTION 07

Frequently Asked Questions

Try It

500 images per month on Starter. Batch-mint URLs for your send list.

Get Your API Key