How can I process the output of my synchronous loop one by one?

Short Answer: Functions in the workflow.

Longer Answer:

You should create the Get request (stripeInvoiceQuery) and the Email (sendEmail) as a function within your workflow and setup the parameters for each as needed. What is currently query2 should then loop as JS Code with something like:

try{
let response = await stripeInvoiceQuery(query1.data[index])
let followUpResponse = await sendEmail(query1.data[index], response.amount_paid)
return followUpResponse
}
catch (error) {
return error
}

This should then send the emails per iteration instead of looping around again at the end. Here's an even more in depth setup example for these functions and how you can try/catch and handle errors following the loop.