Send a Daily Digest Email from Google Sheets Using Apps Script

Instead of opening multiple spreadsheets every morning to check on KPIs, tasks, or reports — let Apps Script pull the data and email you a clean summary automatically.

Basic: email a single sheet's summary

function sendDailyDigest() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName('Summary'); const data = sheet.getDataRange().getValues(); let html = '<h2>Daily Summary</h2><table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;">'; data.forEach((row, i) => { const tag = i === 0 ? 'th' : 'td'; html += '<tr>' + row.map(cell => `<${tag}>${cell}</${tag}>`).join('') + '</tr>'; }); html += '</table>'; GmailApp.sendEmail( Session.getActiveUser().getEmail(), `Daily Digest – ${new Date().toDateString()}`, '', { htmlBody: html } ); Logger.log('Digest sent.'); }

Pull data from multiple sheets

function sendMultiSheetDigest() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheetNames = ['Sales', 'Support Tickets', 'Tasks']; const recipient = '[email protected]'; let html = `<h1 style="font-family:sans-serif;">Daily Digest – ${new Date().toDateString()}</h1>`; sheetNames.forEach(name => { const sheet = ss.getSheetByName(name); if (!sheet) return; const data = sheet.getDataRange().getValues(); html += `<h2 style="font-family:sans-serif;color:#1a73e8;">${name}</h2>`; html += '<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;font-family:sans-serif;font-size:13px;">'; data.forEach((row, i) => { const tag = i === 0 ? 'th' : 'td'; const bg = i === 0 ? 'background:#f1f3f4;' : (i % 2 === 0 ? 'background:#fff;' : 'background:#f8f9fa;'); html += `<tr style="${bg}">` + row.map(cell => `<${tag} style="padding:6px 12px;">${cell}</${tag}>`).join('') + '</tr>'; }); html += '</table><br>'; }); GmailApp.sendEmail(recipient, `Daily Digest – ${new Date().toDateString()}`, '', { htmlBody: html }); Logger.log('Multi-sheet digest sent.'); }

Add KPI highlights at the top

function sendDigestWithKpis() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const kpiSheet = ss.getSheetByName('KPIs'); // Assume KPIs sheet has: Col A = label, Col B = value const kpis = kpiSheet.getDataRange().getValues(); let kpiHtml = '<div style="display:flex;gap:20px;margin-bottom:24px;">'; kpis.forEach(([label, value]) => { kpiHtml += ` <div style="background:#f1f3f4;padding:16px 24px;border-radius:8px;text-align:center;font-family:sans-serif;"> <div style="font-size:24px;font-weight:bold;color:#1a73e8;">${value}</div> <div style="font-size:12px;color:#5f6368;">${label}</div> </div>`; }); kpiHtml += '</div>'; const html = `<h1 style="font-family:sans-serif;">Good morning!</h1>${kpiHtml}`; GmailApp.sendEmail( '[email protected]', `Morning KPI Digest – ${new Date().toDateString()}`, '', { htmlBody: html } ); }

Send to multiple recipients

function sendToTeam() { const recipients = ['[email protected]', '[email protected]', '[email protected]']; const html = '<p>Your daily digest content here.</p>'; recipients.forEach(email => { GmailApp.sendEmail(email, 'Daily Digest', '', { htmlBody: html }); }); }

Schedule it with a daily trigger

function createMorningTrigger() { ScriptApp.newTrigger('sendMultiSheetDigest') .timeBased() .everyDays(1) .atHour(7) // 7 AM in the script's timezone .create(); }

Tips

  • Set your script's timezone in Project Settings so atHour() fires at the right local time.
  • GmailApp.sendEmail has a daily quota of 100 emails for Gmail and 1,500 for Google Workspace.
  • Keep your HTML inline-styled — email clients don't support <style> blocks reliably.
  • Use SpreadsheetApp.openById(id) instead of getActiveSpreadsheet() to pull data from a different spreadsheet than the one the script is bound to.