3. Generate Branded Emails for Your Customers
Build HTML email templates using brand colors, fonts, and logos from Brandparser
Fetch a customer's brand data and generate a ready-to-send HTML email template with their colors, logo, and font styling.
What you'll build
A TypeScript function that takes a brand ID and generates a complete HTML email template -header with logo, brand-colored CTA button, and proper font stacks.
Step 1: Fetch brand data
const API_KEY = process.env.BRANDPARSER_API_KEY!;
const BASE_URL = "https://api.brandparser.com";
async function getBrand(brandId: string) {
const res = await fetch(`${BASE_URL}/v1/api/brands/${brandId}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const { data } = await res.json();
return data;
}Step 2: Extract email-relevant brand data
Email clients have limited CSS support. Extract the essentials:
type EmailBrand = {
primaryColor: string;
primaryHoverColor: string;
buttonTextColor: string;
textColor: string;
backgroundColor: string;
fontStack: string;
logoUrl: string | null;
brandName: string;
};
function extractEmailBrand(brand: any): EmailBrand {
const colors = brand.analysis.colors;
const fonts = brand.analysis.typography.font_families;
const logos = brand.analysis.logos.slots;
const buttons = colors.button_colors?.[0];
const primaryColor = colors.primary_palette[0];
// Build a web-safe font stack from the brand font
const mainFont = fonts[0]?.name ?? "Arial";
const fontStack = `'${mainFont}', Arial, Helvetica, sans-serif`;
// Find the first available logo URL
const logoSlot = Object.values(logos).find(
(slot): slot is { source_url: string } =>
slot !== null && "source_url" in slot
);
return {
primaryColor: primaryColor.hex,
primaryHoverColor: buttons?.hover_background_hex ?? primaryColor.hex,
buttonTextColor: buttons?.text_hex ?? "#FFFFFF",
textColor: "#1a1a1a",
backgroundColor: "#f8f9fa",
fontStack,
logoUrl: logoSlot?.source_url ?? null,
brandName: brand.name,
};
}Step 3: Generate the HTML email
Email templates use tables and inline CSS for maximum compatibility:
function generateBrandedEmail(
emailBrand: EmailBrand,
content: {
heading: string;
body: string;
ctaText: string;
ctaUrl: string;
}
): string {
const { heading, body, ctaText, ctaUrl } = content;
const b = emailBrand;
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body style="margin:0; padding:0; background-color:${b.backgroundColor}; font-family:${b.fontStack};">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center" style="padding:40px 20px;">
<table role="presentation" width="600" cellpadding="0" cellspacing="0"
style="background-color:#ffffff; border-radius:8px; overflow:hidden;">
<!-- Header with logo -->
<tr>
<td style="padding:32px 40px; background-color:${b.primaryColor}; text-align:center;">
${b.logoUrl
? `<img src="${b.logoUrl}" alt="${b.brandName}" height="40"
style="height:40px; width:auto;">`
: `<span style="color:${b.buttonTextColor}; font-size:24px;
font-weight:bold; font-family:${b.fontStack};">${b.brandName}</span>`
}
</td>
</tr>
<!-- Body content -->
<tr>
<td style="padding:40px;">
<h1 style="margin:0 0 16px; font-size:24px; color:${b.textColor};
font-family:${b.fontStack};">
${heading}
</h1>
<p style="margin:0 0 32px; font-size:16px; line-height:1.6;
color:#555555; font-family:${b.fontStack};">
${body}
</p>
<!-- CTA Button -->
<table role="presentation" cellpadding="0" cellspacing="0">
<tr>
<td style="border-radius:6px; background-color:${b.primaryColor};">
<a href="${ctaUrl}"
style="display:inline-block; padding:14px 32px;
color:${b.buttonTextColor}; font-family:${b.fontStack};
font-size:16px; font-weight:600; text-decoration:none;">
${ctaText}
</a>
</td>
</tr>
</table>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="padding:24px 40px; border-top:1px solid #e8e8e8;
text-align:center; font-size:13px; color:#999999;
font-family:${b.fontStack};">
Sent by ${b.brandName}
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>`;
}Step 4: Send via SendGrid
async function sendBrandedEmail(
to: string,
subject: string,
htmlContent: string
) {
const res = await fetch("https://api.sendgrid.com/v3/mail/send", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
personalizations: [{ to: [{ email: to }] }],
from: { email: "hello@yourapp.com" },
subject,
content: [{ type: "text/html", value: htmlContent }],
}),
});
if (!res.ok) {
throw new Error(`SendGrid error: ${res.status}`);
}
}Complete example
const brand = await getBrand("550e8400-e29b-41d4-a716-446655440000");
const emailBrand = extractEmailBrand(brand);
const html = generateBrandedEmail(emailBrand, {
heading: "Your report is ready",
body: "We've finished analyzing your Q4 performance. Click below to view the full breakdown.",
ctaText: "View Report",
ctaUrl: "https://yourapp.com/reports/q4",
});
await sendBrandedEmail("customer@example.com", "Your Q4 Report", html);Tips
- Email font support is limited -most email clients ignore
@font-face. The font stack fallback (Arial, Helvetica, sans-serif) ensures readability everywhere. The brand font will render in Apple Mail, iOS Mail, and some Outlook versions. - Logo format matters -SVG logos may not render in all email clients. If you have a PNG/JPG variant, prefer that. Check the
formatfield in the logo slot. - Inline all CSS -email clients strip
<style>blocks. Every style must be inline. The template above already does this. - Test rendering -use Litmus or Email on Acid to preview across email clients.
Next steps
- White-label your SaaS -scale brand theming to multi-tenant
- Onboard a customer -parse brands and store data for email generation
- Colors schema -full color palette reference