Send Emails with Charts
Learn how to send emails containing data visualizations using charts in your email templates.
Overview
Charts in email templates allow you to include visual data representations like bar charts, line graphs, and pie charts directly in your emails. This is perfect for:
- Weekly/monthly sales reports
- Performance dashboards
- Analytics summaries
- Customer engagement metrics
In emails, charts are automatically rendered as high-resolution static images for maximum compatibility across email clients.
Prerequisites
Before starting, make sure you have:
- An active FormaMail account
- An API key (get one from Settings → API Keys in the dashboard)
- Basic knowledge of JavaScript/Node.js
- Node.js installed on your machine
Tutorial: Send a Weekly Sales Report Email
This tutorial will guide you through creating and sending an email with a chart showing weekly sales data.
Step 1: Create a Template with a Chart
First, create an email template in the dashboard with a chart component:
- Navigate to Templates in your dashboard
- Click Create Template
- Select Email Template
- Name it “Weekly Sales Report”
Add components to your template:
-
Add a Heading component:
- Content:
"Weekly Sales Report - {{reportWeek}}" - Level: H1
- Text align: Center
- Content:
-
Add a Text component:
- Content:
"Generated on {{reportDate}}" - Text align: Center
- Content:
-
Add a Chart component:
- Chart Type: Bar
- Data Source:
{{weeklySales}} - X-Axis Field:
day - Y-Axis Field:
revenue - Title:
Weekly Revenue Performance - Width: 600px
- Height: 400px
-
Add summary statistics (optional):
- Add text components for total revenue, average daily, etc.
-
Save and Publish your template
-
Copy the Template ID (e.g.,
tmpl_abc123)
Variable Schema: When you add the chart component, FormaMail automatically infers that weeklySales should be an array of objects with day and revenue fields.
Step 2: Install Dependencies
Create a new Node.js project and install axios:
mkdir sales-report-email
cd sales-report-email
npm init -y
npm install axiosStep 3: Create the Script
Create a file named send-report.js:
const axios = require('axios');
// Configuration
const API_KEY = 'fm_sk_abc123...'; // Replace with your API key
const API_ENDPOINT = 'https://api.formamail.com/api';
const TEMPLATE_ID = 'tmpl_abc123'; // Replace with your template ID
async function sendWeeklySalesReport() {
try {
// Prepare the email data
const emailData = {
templateId: TEMPLATE_ID,
to: [
{
email: 'manager@yourcompany.com',
name: 'Sales Manager'
}
],
variables: {
// Text variables
reportWeek: 'Week 47, 2025',
reportDate: new Date().toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
}),
// Chart data - array of objects
weeklySales: [
{ day: 'Monday', revenue: 12500 },
{ day: 'Tuesday', revenue: 15200 },
{ day: 'Wednesday', revenue: 13800 },
{ day: 'Thursday', revenue: 16500 },
{ day: 'Friday', revenue: 18200 },
{ day: 'Saturday', revenue: 21000 },
{ day: 'Sunday', revenue: 14500 }
],
// Summary metrics (optional)
totalRevenue: 111700,
averageDaily: 15957,
growthPercent: 12.5
}
};
// Send the email
const response = await axios.post(
`${API_ENDPOINT}/emails/send`,
emailData,
{
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
}
);
console.log('✅ Sales report sent successfully!');
console.log('Email ID:', response.data.id);
console.log('Status:', response.data.status);
return response.data;
} catch (error) {
console.error('❌ Error sending sales report:');
console.error('Status:', error.response?.status);
console.error('Error:', error.response?.data || error.message);
throw error;
}
}
// Run the function
sendWeeklySalesReport()
.then(() => console.log('\nDone!'))
.catch(() => process.exit(1));Step 4: Run the Script
Execute the script to send the email:
node send-report.jsYou should see output like:
✅ Sales report sent successfully!
Email ID: email_xyz789
Status: queued
Done!Step 5: Verify the Email
- Check your inbox at
manager@yourcompany.com - The email should contain:
- The heading with your report week
- A bar chart showing daily revenue
- Any summary statistics you added
The chart will be rendered as a high-quality PNG image embedded directly in the email.
Advanced Examples
Example 1: Multiple Charts in One Email
Send an email with multiple charts for a comprehensive dashboard:
const emailData = {
templateId: 'tmpl_dashboard',
to: [{ email: 'executive@company.com', name: 'CEO' }],
variables: {
// Chart 1: Revenue trend (line chart)
monthlyRevenue: [
{ month: 'Jan', revenue: 45000 },
{ month: 'Feb', revenue: 52000 },
{ month: 'Mar', revenue: 48000 },
{ month: 'Apr', revenue: 58000 }
],
// Chart 2: Category breakdown (pie chart)
revenueByCategory: [
{ category: 'Products', amount: 85000 },
{ category: 'Services', amount: 45000 },
{ category: 'Consulting', amount: 30000 },
{ category: 'Support', amount: 15000 }
],
// Chart 3: Regional performance (bar chart)
regionalSales: [
{ region: 'North America', sales: 95000 },
{ region: 'Europe', sales: 62000 },
{ region: 'Asia Pacific', sales: 48000 },
{ region: 'Latin America', sales: 28000 }
]
}
};Template Setup: Add three chart components in your template, each with different chart types and data sources.
Example 2: Dynamic Chart Data from Database
Fetch real data from your database and send it in an email:
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function sendRealtimeSalesReport() {
// Fetch sales data from database
const salesData = await prisma.sale.groupBy({
by: ['date'],
where: {
date: {
gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) // Last 7 days
}
},
_sum: {
amount: true
},
orderBy: {
date: 'asc'
}
});
// Transform data for chart
const chartData = salesData.map(day => ({
date: day.date.toLocaleDateString('en-US', { weekday: 'long' }),
revenue: day._sum.amount
}));
// Send email with real data
await axios.post(`${API_ENDPOINT}/emails/send`, {
templateId: 'tmpl_sales_report',
to: [{ email: 'manager@company.com' }],
variables: {
reportDate: new Date().toISOString(),
weeklySales: chartData,
totalRevenue: chartData.reduce((sum, day) => sum + day.revenue, 0)
}
}, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
});
console.log('Real-time sales report sent!');
}Example 3: Scheduled Daily Reports
Use a cron job or task scheduler to send daily reports automatically:
const cron = require('node-cron');
// Schedule to run every day at 9 AM
cron.schedule('0 9 * * *', async () => {
console.log('Sending daily sales report...');
try {
await sendWeeklySalesReport();
console.log('Daily report sent successfully!');
} catch (error) {
console.error('Failed to send daily report:', error);
// Optional: Send alert to ops team
}
});
console.log('Daily report scheduler started.');
console.log('Reports will be sent every day at 9:00 AM.');Install the cron package:
npm install node-cronChart Data Format Reference
Bar/Line/Area Charts
Best for time series or categorical data:
{
chartData: [
{ label: 'Q1 2025', value: 125000 },
{ label: 'Q2 2025', value: 142000 },
{ label: 'Q3 2025', value: 138000 },
{ label: 'Q4 2025', value: 165000 }
]
}Pie/Doughnut Charts
Best for proportions (limit to 5-7 categories):
{
categoryBreakdown: [
{ label: 'Product Sales', value: 45 },
{ label: 'Services', value: 30 },
{ label: 'Subscriptions', value: 15 },
{ label: 'Other', value: 10 }
]
}Scatter Charts
Best for correlation analysis:
{
correlationData: [
{ x: 100, y: 200 },
{ x: 150, y: 280 },
{ x: 200, y: 320 },
{ x: 250, y: 410 }
]
}Best Practices
1. Keep Data Concise
✅ Good: 7-10 data points
weeklySales: [
{ day: 'Mon', revenue: 12500 },
{ day: 'Tue', revenue: 15200 },
// ... 7 days total
]❌ Bad: 50+ data points (too crowded for email)
2. Use Appropriate Chart Types
| Data Type | Best Chart |
|---|---|
| Trends over time | Line chart |
| Comparing categories | Bar chart |
| Proportions/percentages | Pie/doughnut |
| Multiple data series | Area chart (stacked) |
| Correlation | Scatter chart |
3. Optimize for Email Clients
- Width: Max 600px (fits most email clients)
- Height: 300-400px (readable without scrolling)
- Colors: Use high-contrast colors
- Labels: Keep axis labels short
4. Test Before Production
Send test emails to yourself first:
const emailData = {
templateId: TEMPLATE_ID,
to: [{ email: 'your-email@company.com' }], // Your test email
variables: {
// ... your data
}
};View the email in different clients:
- Gmail
- Outlook
- Apple Mail
- Mobile devices
Troubleshooting
Chart Not Appearing
Issue: Email arrives but chart is missing or broken.
Solutions:
- ✅ Verify template has a chart component
- ✅ Check data source variable name matches (e.g.,
{{weeklySales}}) - ✅ Ensure data is an array of objects
- ✅ Verify xAxis and yAxis field names exist in your data
Data Not Rendering Correctly
Issue: Chart appears but shows wrong data or no data.
Solutions:
- ✅ Check field names in your data match xAxis/yAxis settings
- ✅ Ensure numeric values are numbers, not strings
- ✅ Verify array is not empty
- ✅ Check for null or undefined values in data
Chart Looks Blurry
Issue: Chart image quality is poor.
Solutions:
- ✅ Increase chart width/height in template
- ✅ Charts are automatically rendered at 2x resolution
- ✅ Use simple chart types (bar/line) for better clarity
Next Steps
- Attachments: Learn to include PDF reports with native charts in Generate PDF Invoices
- Bulk Emails: Send personalized reports to multiple recipients in Send Bulk Personalized Emails
- Templates: Deep dive into template design in Create an Email Template
- API Reference: Full chart component documentation in User Guide - Components