Home / Blog / Email a Report Automatically
How-to · 2026

How to Email an Excel Report Automatically

Getting the report to update itself is only half the job — someone still has to send it. Here are the four routes that put a finished report in people’s inboxes on a schedule, and what each one costs you to maintain.

By the Quiriz Team · Published August 5, 2026 · 8 min read

The quick answer: Power Automate → Recurrence trigger → Get file content → Send an email (V2) with an attachment. That covers most cases without a line of code. The rest of this is the detail that decides whether it still works in three months — refreshing the data first, what to do when the file is not in OneDrive, and the Sheets equivalent.

Automating a report is two jobs, not one

People usually solve the first half — making the analysis recalculate on new data — and then keep doing the second half by hand every Monday. On the Excel forums it reads the same way every time: "I email individually 6 excel reports weekly to all 30+ managers, is there any way I can eliminate this redundant task." The refresh was never the expensive part. The sending is.

So decide up front which half you are automating. If the workbook still needs a human to re-point ranges, fix that first — stop rebuilding the report every week covers it. Everything below assumes the file produces the right numbers when it opens.

1. Power Automate: the no-code route

This is the one to reach for first. It runs in the cloud, so nothing depends on your laptop being awake.

  1. Move the workbook to OneDrive for Business or SharePoint. Non-negotiable — cloud flows cannot read a local path or a mapped network drive.
  2. In Power Automate, create a Scheduled cloud flow. The Recurrence trigger takes an interval, a frequency, and a timezone. Set the timezone explicitly, or the run drifts relative to your working day.
  3. Add OneDrive for Business → Get file content and pick the workbook.
  4. Add Office 365 Outlook → Send an email (V2). Fill in To, Subject and Body, then open Advanced parameters and add an attachment: Attachments Name is the file name including the extension, Attachments Content is the File Content output from step 3.

Two things that trip people up. The attachment name must include .xlsx or Outlook sends something the recipient cannot open. And if you want the date in the subject line, use an expression such as formatDateTime(utcNow(),'MMMM yyyy') rather than typing the month in and forgetting to change it.

2. Refresh the data before it sends

A flow that attaches the file without refreshing sends whatever was cached the last time a human opened it. That failure is quiet — the report arrives on time, looking correct, with last month's numbers.

The fix is an Office Script. In Excel on the web, open Automate → New Script and write a small script that refreshes the connections and recalculates:

function main(workbook: ExcelScript.Workbook) {
  workbook.refreshAllDataConnections();
  workbook.getApplication().calculate(ExcelScript.CalculationType.full);
}

Then in the flow, insert Excel Online (Business) → Run script before the Get file content step. Note the limit honestly: Office Scripts refresh what the web client can reach. Power Query queries that hit an on-premises database through a gateway will not refresh here — those need the desktop app, which pushes you toward route 3.

3. VBA plus Task Scheduler: still works, ages badly

The classic answer is a macro that refreshes the workbook and hands it to Outlook, launched by Windows Task Scheduler:

Sub SendReport()
    ThisWorkbook.RefreshAll
    Application.CalculateUntilAsyncQueriesDone
    ThisWorkbook.Save
    With CreateObject("Outlook.Application").CreateItem(0)
        .To = "team@example.com"
        .Subject = "Weekly report " & Format(Date, "d mmm yyyy")
        .Body = "Attached is this week's report."
        .Attachments.Add ThisWorkbook.FullName
        .Send
    End With
End Sub

It works, and if your data source only exists on your machine it may be the only thing that works. Be clear-eyed about the cost: it needs that PC powered on and signed in, Outlook installed and open, macros enabled, and someone to notice when a Windows update quietly breaks the scheduled task. Treat it as the fallback, not the default.

4. The Google Sheets version

Same shape, different plumbing. In Extensions → Apps Script:

function emailReport() {
  const ss = SpreadsheetApp.getActive();
  SpreadsheetApp.flush();
  const pdf = ss.getAs('application/pdf').setName('Weekly report.pdf');
  MailApp.sendEmail({
    to: 'team@example.com',
    subject: 'Weekly report ' + Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'd MMM yyyy'),
    body: 'Attached is this week\'s report.',
    attachments: [pdf],
  });
}

Then Triggers → Add Trigger, choose emailReport, time-driven, week timer, and pick the day and hour. Watch the daily quota on a consumer Gmail account if you are sending to a long list — Workspace accounts get a much higher allowance.

Put the answer in the email, not only in the attachment

Whichever route you pick, the attachment is the part most recipients never open. Three or four lines in the body — the headline number, the change since last period, and the one sentence explaining it — get read on a phone. The workbook is for the person who wants to check your work.

The part none of these routes solve

Every option above ships a file on a timer. What none of them handle is the reply that arrives twenty minutes later: "can you also break this out by region?" That question comes back to you, by hand, every cycle — which is how a report you automated still costs you an hour a week.

That gap is the reason we built scheduled reports into Quiriz the way we did. You ask the question once in plain English, save the answer as a report, and schedule it — no ranges to re-point, no flow to maintain. The difference is what happens afterwards: recipients can ask their own follow-ups against the same dataset, in the app or by @mentioning the Slack bot, instead of queueing behind whoever owns the workbook. In Excel the same question can sit in a cell as =QUIRIZ.ASK("revenue by region this month vs last", "table") and re-answer on recalculation.

Honest caveat: scheduled reports and the Slack bot are on the paid tier, and if your report is a fixed table that nobody ever asks a follow-up about, a Power Automate flow is genuinely the right tool and it costs nothing.

Whatever you build, send yourself a test run before you add the real recipient list. Wrong-recipient and stale-data mistakes are both silent, and both get noticed by the wrong person first.

Stop being the person who sends the weekly report

Ask your question in plain English, save it as a report, and schedule it — then let your team ask their own follow-ups from the same data. Free to start.

Try Quiriz free →

Frequently asked questions

Can Excel email a report automatically without VBA?
Yes. A Power Automate scheduled cloud flow can send an Excel file on a recurrence with no code: Recurrence trigger, then OneDrive for Business "Get file content", then Office 365 Outlook "Send an email (V2)" with the file attached. The workbook has to live in OneDrive or SharePoint for the flow to reach it.
How do I refresh the data before the report is sent?
Add an Office Scripts step before the send. In Excel on the web, record or write a script that calls workbook.refreshAllDataConnections() (or rebuilds your summary sheet), then call it from the flow with the Excel Online (Business) "Run script" action. Power Query refreshes that depend on a desktop gateway will not run in a cloud flow.
Why does my scheduled report arrive with stale numbers?
Almost always because the flow attached the file without refreshing it first. The saved workbook holds the values from the last time someone opened it. Either refresh in the flow with Office Scripts, or point the report at a source that recalculates server-side.
How do I do this in Google Sheets instead?
Use Apps Script. Write a function that builds the summary and calls MailApp.sendEmail with the sheet exported as a PDF or the summary in the body, then add a time-driven trigger under Triggers to run it weekly. No add-on required.