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
functionsendDailyDigest(){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 – ${newDate().toDateString()}`,'',{htmlBody: html });Logger.log('Digest sent.');}
Pull data from multiple sheets
functionsendMultiSheetDigest(){const ss =SpreadsheetApp.getActiveSpreadsheet();const sheetNames =['Sales','Support Tickets','Tasks'];const recipient ='[email protected]';let html =`<h1 style="font-family:sans-serif;">Daily Digest – ${newDate().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 – ${newDate().toDateString()}`,'',{htmlBody: html });Logger.log('Multi-sheet digest sent.');}
Add KPI highlights at the top
functionsendDigestWithKpis(){const ss =SpreadsheetApp.getActiveSpreadsheet();const kpiSheet = ss.getSheetByName('KPIs');// Assume KPIs sheet has: Col A = label, Col B = valueconst 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 – ${newDate().toDateString()}`,'',{htmlBody: html });}
Send to multiple recipients
functionsendToTeam(){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
functioncreateMorningTrigger(){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.