TutorialsSend Emails with Charts

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:

  1. Navigate to Templates in your dashboard
  2. Click Create Template
  3. Select Email Template
  4. Name it “Weekly Sales Report”

Add components to your template:

  1. Add a Heading component:

    • Content: "Weekly Sales Report - {{reportWeek}}"
    • Level: H1
    • Text align: Center
  2. Add a Text component:

    • Content: "Generated on {{reportDate}}"
    • Text align: Center
  3. 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
  4. Add summary statistics (optional):

    • Add text components for total revenue, average daily, etc.
  5. Save and Publish your template

  6. 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 axios

Step 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.js

You should see output like:

✅ Sales report sent successfully!
Email ID: email_xyz789
Status: queued

Done!

Step 5: Verify the Email

  1. Check your inbox at manager@yourcompany.com
  2. 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-cron

Chart 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 TypeBest Chart
Trends over timeLine chart
Comparing categoriesBar chart
Proportions/percentagesPie/doughnut
Multiple data seriesArea chart (stacked)
CorrelationScatter 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:

  1. ✅ Verify template has a chart component
  2. ✅ Check data source variable name matches (e.g., {{weeklySales}})
  3. ✅ Ensure data is an array of objects
  4. ✅ 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:

  1. ✅ Check field names in your data match xAxis/yAxis settings
  2. ✅ Ensure numeric values are numbers, not strings
  3. ✅ Verify array is not empty
  4. ✅ Check for null or undefined values in data

Chart Looks Blurry

Issue: Chart image quality is poor.

Solutions:

  1. ✅ Increase chart width/height in template
  2. ✅ Charts are automatically rendered at 2x resolution
  3. ✅ Use simple chart types (bar/line) for better clarity

Next Steps