Skip to main content
Community site session details

Community site session details

Session Id :

Bulk Email Sender

wyattdave Profile Picture Posted by wyattdave 406 Super User 2025 Season 1

The flow allows the user to send bulk emails with a dynamic html template. With the addition of a 2 email test run to validate before approval to send all emails 

 

Setup

  1. To run the flow you will require: OneDrive for Business, Shared Outlook Mailbox, Excel Online (with Office Script) - though the flow could be edited to work withoot OneDrive for Business or Shared Outlook mailbox
  2. Unzup attached file and Import the BulkEmailerwithOfficeScript.zip file into your power automate environment
  3. Download and save the 'Bulk Email Conversion.ost' to your OneDrive/Documents/Office Scripts' folder
  4. Download the 2 example files 
  5. Edit the flow and ensure the OneDrive route directory is selected and the Office Script

     

    davedidisco_0-1647260367320.png
  6. Setup your list of email address, parameters/variables and your html template. The flow will take each header from the table and use it to replace that value in the template e.g below the {Name} header will replace {Name} with Dan in the template

     

    davedidisco_1-1647260572691.png

 

The Flow completes the followin steps

  • Creates a copy of the excel list file on your one drive to ruin the script against
  • Runs the 'Bulk Email Conversion' script to pivot the table into a row per variable to replace and gives each email a integer ID

davedidisco_0-1647264761297.png

 

 

function main(workbook: ExcelScript.Workbook) {
	let wb1 = workbook.getWorksheet("Sheet1");
	let wb2 = workbook.addWorksheet();
	let i = 1;
	let r=1;
	let c=3;
	let rowCount = wb1.getUsedRange().getRowCount();
	let colCount = wb1.getUsedRange().getColumnCount();
	console.log(rowCount+" "+colCount);
	let headersMain =[["Email","Subject"]]
	wb1.getRange("A1:B1").setValue(headersMain);
	let headers=[["ID","Email","Change","With"]]
	wb2.getRange("A1:D1").setValue(headers);

	for (r=1;r <rowCount;r++){

		for(c=2;c<colCount;c++){
		
			wb2.getCell(i, 0).setValue(r);
			wb2.getCell(i, 1).setValue(wb1.getCell(r, 0).getValue());
			wb2.getCell(i, 2).setValue(wb1.getCell(0, c).getValue());
			wb2.getCell(i, 3).setValue(wb1.getCell(r, c).getValue());
			i++;
		}
	}
	wb1.getRange("A:A").insert(ExcelScript.InsertShiftDirection.right);
	wb1.getRange("A1").setValue("mainID");
	wb1.getRange("A2").setFormulaLocal("=row(A1)");
	wb1.getRange("A2").autoFill();

	let table1 = workbook.addTable(wb1.getRange("A1:F"+rowCount), true);
	table1.setName("mainTable");
	let table2 =workbook.addTable(wb2.getRange("A1:D" + i), true);
	table2.setName("PivotTable");
	wb2.setName("Pivot");

	return(rowCount-1);
}

 

 

  • Gets the pivoted table rows
  • The rows are then filtered by id using sequential integer, with the 'Do Until' only doing the first 2 emails (Preview) and changing send to the user who triggered the flow
  • The flow then loops over the filtered rows and carries out a find and replace on the html template

     

    davedidisco_2-1647261025972.png

 

replace(variables('sEmailbody'), items('Apply_to_each_3')?['Change'], items('Apply_to_each_3')?['with'])​

 

 

  •  Sends 2 test emails and then an approval request 
  • If sample is correct the emails are approved the the flow will repeat preview stage but send all emails and to the listed email address
davedidisco_4-1647262429063.png

 

 

 

Categories:

Comments

  • Dave48 Profile Picture Dave48 63
    Posted at
    Bulk Email Sender

    Hi Yutao,

    Great feedback, didn't think of looping of over an array instead of a range, would definitely I prove performance and an all round nicer solution

  • Yutao Huang Profile Picture Yutao Huang Microsoft Employee
    Posted at
    Bulk Email Sender

    Thanks for sharing! This is a very useful solution 👍!

     

    Here is a minor performance suggestion to the code around the for/loop block - instead of calling getCell, setValue, getValue frequently inside the loops, you can also try using getValues first to get all the cell values into a two-dimensional string array, then iterate through it and build up another two-dimensional string array based on your current pivoting logic, and finally call setValues to set the second array into the target range in a single shot. This sometimes can greatly improve the script performance especially for large worksheet that contains many rows and columns.