Emails customers a polite reminder with the invoice attached at 3, 14 and 30 days overdue, and sends you a morning summary of what's owed.
Uses
Gmail
QuickBooks Online
Chase overdue QuickBooks invoices
summaryEmail to blank.Set summaryEmail to blank.sendToCustomers to false.Set sendToCustomers to false.signOffName to blank.Set signOffName to blank.firstReminderDays to 3.Set firstReminderDays to 3.secondReminderDays to 14.Set secondReminderDays to 14.thirdReminderDays to 30.Set thirdReminderDays to 30.liveMode to false.Set liveMode to false.sendToCustomers is yesIf sendToCustomers is yesYes
liveMode to true.Change liveMode to true.Else if @sendToCustomers isn't no
Otherwise
No steps
today.Get today's date and save it as today.reminderHistory to an empty list.Set reminderHistory to an empty list.historyErrorIf a step below fails, save the error as historyErrorTry
storedHistory.Get the stored value 'invoice_reminder_history'. Save it as storedHistory.storedHistory.found is yesIf storedHistory.found is yesYes
reminderHistory to storedHistory.value.Change reminderHistory to storedHistory.value.No
No steps
On error
historyError.message.Stop and report a problem: Couldn't read the record of reminders already sent, so nothing was sent this morning: that record is what stops a customer being chased twice. Lodol said: historyError.message.businessName to blank.Set businessName to blank.overdueInvoices to an empty list.Set overdueInvoices to an empty list.nextPage to 1.Set nextPage to 1.morePages to true.Set morePages to true.quickbooksErrorIf a step below fails, save the error as quickbooksErrorTry
signOffName is blankIf signOffName is blankYes
company.Get QuickBooks company info. Save it as company.company.CompanyInfo.CompanyName and save it as businessName.Trim company.CompanyInfo.CompanyName and save it as businessName.No
signOffName and save it as businessName.Trim signOffName and save it as businessName.morePages is yes:While morePages is yes:overduePage. List up to 1000 QuickBooks invoices. Save it as overduePage.overdueInvoices and overduePage.QueryResponse.Invoice into one list and save it as overdueInvoices. Combine overdueInvoices and overduePage.QueryResponse.Invoice into one list and save it as overdueInvoices.morePages to overduePage.has_more. Change morePages to overduePage.has_more.nextPage to overduePage.next_start_position. Change nextPage to overduePage.next_start_position.On error
quickbooksError.message.Stop and report a problem: QuickBooks couldn't be read, so no reminders were sent this morning. Check that QuickBooks is still connected in Lodol. QuickBooks said: quickbooksError.message.businessName is blankIf businessName is blankYes
No
No steps
overdueInvoices and save it as overdueInvoices.Keep only Id, DocNumber, TxnDate, DueDate, Balance, TotalAmt, CurrencyRef, CustomerRef, and BillEmail in overdueInvoices and save it as overdueInvoices.overdueInvoices by DueDate, smallest first and save it as overdueInvoices.Sort overdueInvoices by DueDate, smallest first and save it as overdueInvoices.overdueInvoices with reminderHistory by Id and invoice_id and save it as overdueInvoices.Match overdueInvoices with reminderHistory by Id and invoice_id and save it as overdueInvoices.overdueNow to an empty list.Set overdueNow to an empty list.remindersDue to an empty list.Set remindersDue to an empty list.stillOverdueLines to an empty list.Set stillOverdueLines to an empty list.updatedHistory to an empty list.Set updatedHistory to an empty list.invoice in overdueInvoices:For each invoice in overdueInvoices:invoice.DueDate to today and save it as daysOverdue.Count the days from invoice.DueDate to today and save it as daysOverdue.daysOverdue is less than 1 or invoice.Balance is less than or equal to 0If daysOverdue is less than 1 or invoice.Balance is less than or equal to 0Yes
No
No steps
overdueNow and save it as overdueNow.Add a record of currency and balance to the end of overdueNow and save it as overdueNow.stageReached to 0.Set stageReached to 0.daysOverdue is greater than or equal to thirdReminderDaysIf daysOverdue is greater than or equal to thirdReminderDaysYes
stageReached to 3.Change stageReached to 3.Else if @daysOverdue is greater than or equal to @secondRem…
stageReached to 2.Change stageReached to 2.Else if @daysOverdue is greater than or equal to @firstRemi…
stageReached to 1.Change stageReached to 1.Otherwise
No steps
stageSent to 0.Set stageSent to 0.stageFlagged to 0.Set stageFlagged to 0.invoice.due_date is invoice.DueDateIf invoice.due_date is invoice.DueDateYes
stageSent to invoice.reminder_stage.Change stageSent to invoice.reminder_stage.stageFlagged to invoice.flagged_stage.Change stageFlagged to invoice.flagged_stage.updatedHistory and save it as updatedHistory.Add a record of invoice id, due date, reminder stage, and flagged stage to the end of updatedHistory and save it as updatedHistory.No
No steps
numberStyle to thousands.Set numberStyle to thousands.invoice.CurrencyRef.value is 3If the length of invoice.CurrencyRef.value is 3Yes
numberStyle to currency.Change numberStyle to currency.No
No steps
invoice.Balance as a number and save it as balanceText.Format invoice.Balance as a number and save it as balanceText.amountText to balanceText.Set amountText to balanceText.invoice.Balance is less than invoice.TotalAmtIf invoice.Balance is less than invoice.TotalAmtYes
invoice.TotalAmt as a number and save it as totalText.Format invoice.TotalAmt as a number and save it as totalText.@balanceText still to pay of @totalText and save it as amountText.Build the text @balanceText still to pay of @totalText and save it as amountText.No
No steps
invoice.DueDate readable as “November 2, 2026” and save it as dueDateText.Make invoice.DueDate readable as “November 2, 2026” and save it as dueDateText.invoiceName to invoice.DocNumber.Set invoiceName to invoice.DocNumber.invoice.DocNumber is emptyIf invoice.DocNumber is emptyYes
invoice.TxnDate readable as “November 2, 2026” and save it as issuedText.Make invoice.TxnDate readable as “November 2, 2026” and save it as issuedText.invoiceName to dated issuedText.Change invoiceName to dated issuedText.No
No steps
daysText to daysOverdue days overdue.Set daysText to daysOverdue days overdue.daysOverdue is 1If daysOverdue is 1Yes
daysText to 1 day overdue.Change daysText to 1 day overdue.No
No steps
• @invoice.CustomerRef.name, invoice @invoiceName: @amountText, @daysText and save it as summaryLine.Build the text • @invoice.CustomerRef.name, invoice @invoiceName: @amountText, @daysText and save it as summaryLine.stageReached is greater than stageSentIf stageReached is greater than stageSentYes
invoice and save it as dueForReminder.Merge a record of stage reached, stage sent, stage flagged, and 5 more into invoice and save it as dueForReminder.dueForReminder to the end of remindersDue and save it as remindersDue.Add dueForReminder to the end of remindersDue and save it as remindersDue.No
progress to first reminder goes out at firstReminderDays days overdue.Set progress to first reminder goes out at firstReminderDays days overdue.stageSent is 3If stageSent is 3Yes
progress to third and last reminder sent.Change progress to third and last reminder sent.Else if @stageSent is 2
second reminder sent; the third goes out at @thirdReminderDays days overdue and save it as progress.Build the text second reminder sent; the third goes out at @thirdReminderDays days overdue and save it as progress.Else if @stageSent is 1
first reminder sent; the second goes out at @secondReminderDays days overdue and save it as progress.Build the text first reminder sent; the second goes out at @secondReminderDays days overdue and save it as progress.Otherwise
No steps
summaryLine (progress) to the end of stillOverdueLines and save it as stillOverdueLines.Add summaryLine (progress) to the end of stillOverdueLines and save it as stillOverdueLines.remindersDue by CustomerRef.value and save it as customersToChase.Group the items in remindersDue by CustomerRef.value and save it as customersToChase.chasedLines to an empty list.Set chasedLines to an empty list.chasedCount to 0.Set chasedCount to 0.noEmailLines to an empty list.Set noEmailLines to an empty list.problems to an empty list.Set problems to an empty list.examples to an empty list.Set examples to an empty list.sampledStages to an empty list.Set sampledStages to an empty list.sampleAttachments to an empty list.Set sampleAttachments to an empty list.sentVerb to would go to .Set sentVerb to would go to .liveMode is yesIf liveMode is yesYes
sentVerb to sent to .Change sentVerb to sent to .No
No steps
customer in customersToChase:For each customer in customersToChase:customer.items and save it as firstInvoice.Get the first item of customer.items and save it as firstInvoice.BillEmail.Address from every item in customer.items and save it as billEmails.Get BillEmail.Address from every item in customer.items and save it as billEmails.billEmails and save it as knownEmails.Remove duplicates and empty items from billEmails and save it as knownEmails.knownEmails with , and save it as sendTo.Join knownEmails with , and save it as sendTo.customer.key is blankIf customer.key is blankYes
sendTo to blank.Change sendTo to blank.No
No steps
sendTo is blank and customer.key isn't blankIf sendTo is blank and customer.key isn't blankYes
lookupErrorIf a step below fails, save the error as lookupErrorTry
customer.key. Save it as customerRecord.Get QuickBooks customer customer.key. Save it as customerRecord.customerRecord.Customer.PrimaryEmailAddr.Address and save it as sendTo.Trim customerRecord.Customer.PrimaryEmailAddr.Address and save it as sendTo.On error
firstInvoice.CustomerRef.name: couldn't look up their email address in QuickBooks (lookupError.message), so no reminder went out. It will be tried again on the next run. to the end of problems and save it as problems.Add • firstInvoice.CustomerRef.name: couldn't look up their email address in QuickBooks (lookupError.message), so no reminder went out. It will be tried again on the next run. to the end of problems and save it as problems.No
No steps
sendTo is blankIf sendTo is blankYes
unreachable in customer.items:For each unreachable in customer.items:unreachable.stage_reached is greater than unreachable.stage_flagged If unreachable.stage_reached is greater than unreachable.stage_flaggedYes
unreachable.summary_line: there's no email address on the invoice or on the customer in QuickBooks, so it can't be chased. Add one and its reminder goes out on the next run. to the end of noEmailLines and save it as noEmailLines.Add unreachable.summary_line: there's no email address on the invoice or on the customer in QuickBooks, so it can't be chased. Add one and its reminder goes out on the next run. to the end of noEmailLines and save it as noEmailLines.updatedHistory where item.invoice_id is not unreachable.Id and save it as historyWithoutUnreachable.Keep each item in updatedHistory where item.invoice_id is not unreachable.Id and save it as historyWithoutUnreachable.historyWithoutUnreachable and save it as updatedHistory.Add a record of invoice id, due date, reminder stage, and flagged stage to the end of historyWithoutUnreachable and save it as updatedHistory.No
unreachable.summary_line (no email address in QuickBooks, so not chased) to the end of stillOverdueLines and save it as stillOverdueLines.Add unreachable.summary_line (no email address in QuickBooks, so not chased) to the end of stillOverdueLines and save it as stillOverdueLines.No
No steps
stage_reached from every item in customer.items and save it as stagesReached.Get stage_reached from every item in customer.items and save it as stagesReached.stagesReached and save it as reminderStage.Find the largest number in stagesReached and save it as reminderStage.writeEmail to true.Set writeEmail to true.liveMode is no and sampledStages contains reminderStageIf liveMode is no and sampledStages contains reminderStageYes
writeEmail to false.Change writeEmail to false.No
No steps
writeEmail is yesIf writeEmail is yesYes
invoicePdfs to an empty list.Set invoicePdfs to an empty list.pdfProblem to blank.Set pdfProblem to blank.pdfInvoice in customer.items:For each pdfInvoice in customer.items:pdfError If a step below fails, save the error as pdfErrorTry
pdfInvoice. Save it as invoicePdf.Get the PDF of QuickBooks invoice pdfInvoice. Save it as invoicePdf.invoicePdf.document_ref to the end of invoicePdfs and save it as invoicePdfs.Add invoicePdf.document_ref to the end of invoicePdfs and save it as invoicePdfs.On error
@pdfInvoice.summary_line: couldn't get the invoice PDF from QuickBooks (@pdfError.message), so no reminder went out. It will be tried again on the next run. and save it as pdfProblem.Build the text @pdfInvoice.summary_line: couldn't get the invoice PDF from QuickBooks (@pdfError.message), so no reminder went out. It will be tried again on the next run. and save it as pdfProblem.pdfProblem isn't blankIf pdfProblem isn't blankYes
pdfProblem to the end of problems and save it as problems.Add pdfProblem to the end of problems and save it as problems.No
No steps
invoiceRef to invoice firstInvoice.invoice_name.Set invoiceRef to invoice firstInvoice.invoice_name.thisInvoice to this invoice.Set thisInvoice to this invoice.copyNote to A copy of the invoice is attached.Set copyNote to A copy of the invoice is attached.customer.count is greater than 1If customer.count is greater than 1Yes
invoiceRef to customer.count invoices.Change invoiceRef to customer.count invoices.thisInvoice to these invoices.Change thisInvoice to these invoices.copyNote to A copy of each invoice is attached.Change copyNote to A copy of each invoice is attached.No
No steps
Friendly reminder: @invoiceRef from @businessName and save it as emailSubject.Build the text Friendly reminder: @invoiceRef from @businessName and save it as emailSubject.We hope all is well. This is a friendly reminder that payment for @thisInvoice is now past due: and save it as opening.Build the text We hope all is well. This is a friendly reminder that payment for @thisInvoice is now past due: and save it as opening.@copyNote for convenience. If payment is already on its way, thank you, and please disregard this note. If anything looks wrong, just reply to this email and w... and save it as closing.Build the text @copyNote for convenience. If payment is already on its way, thank you, and please disregard this note. If anything looks wrong, just reply to this email and w... and save it as closing.reminderStage is 3If reminderStage is 3Yes
Payment overdue: @invoiceRef from @businessName and save it as emailSubject.Build the text Payment overdue: @invoiceRef from @businessName and save it as emailSubject.Payment for @thisInvoice is now well past due, and we haven't yet received it: and save it as opening.Build the text Payment for @thisInvoice is now well past due, and we haven't yet received it: and save it as opening.@copyNote. We'd be grateful if you could arrange payment as soon as possible, or reply to let us know when to expect it. If something is holding it up, please ... and save it as closing.Build the text @copyNote. We'd be grateful if you could arrange payment as soon as possible, or reply to let us know when to expect it. If something is holding it up, please ... and save it as closing.Else if @reminderStage is 2
Following up: @invoiceRef from @businessName and save it as emailSubject.Build the text Following up: @invoiceRef from @businessName and save it as emailSubject.We're following up because our records still don't show payment for @thisInvoice: and save it as opening.Build the text We're following up because our records still don't show payment for @thisInvoice: and save it as opening.@copyNote. Could you let us know when we can expect payment? If you've already paid, thank you, and please let us know so we can update our records. If anythin... and save it as closing.Build the text @copyNote. Could you let us know when we can expect payment? If you've already paid, thank you, and please let us know so we can update our records. If anythin... and save it as closing.Otherwise
No steps
customerLines to an empty list.Set customerLines to an empty list.listedInvoice in customer.items:For each listedInvoice in customer.items:listedInvoice.invoice_name: listedInvoice.amount_text, due listedInvoice.due_date_text (listedInvoice.days_text) to the end of customerLines and save it as customerLines. Add • Invoice listedInvoice.invoice_name: listedInvoice.amount_text, due listedInvoice.due_date_text (listedInvoice.days_text) to the end of customerLines and save it as customerLines.customerLines with a new line and save it as invoiceList.Join customerLines with a new line and save it as invoiceList.greetName to firstInvoice.CustomerRef.name.Set greetName to firstInvoice.CustomerRef.name.greetName contains :If greetName contains :Yes
: in greetName and save it as greetName.Get the text before : in greetName and save it as greetName.No
No steps
Hi @greetName, @opening @invoiceList @closing Kind regards, @businessName and save it as reminderBody.Build the text Hi @greetName, @opening @invoiceList @closing Kind regards, @businessName and save it as reminderBody.liveMode is yesIf liveMode is yesYes
sendErrorIf a step below fails, save the error as sendErrorTry
sendTo.Send an email to sendTo.
Subject: emailSubjectreminderBodyOn error
firstInvoice.CustomerRef.name: the reminder for invoiceRef couldn't be sent to sendTo (sendError.message). It will be tried again on the next run. to the end of problems and save it as problems.Add • firstInvoice.CustomerRef.name: the reminder for invoiceRef couldn't be sent to sendTo (sendError.message). It will be tried again on the next run. to the end of problems and save it as problems.sentInvoice in customer.items:For each sentInvoice in customer.items:updatedHistory where item.invoice_id is not sentInvoice.Id and save it as historyWithoutSent. Keep each item in updatedHistory where item.invoice_id is not sentInvoice.Id and save it as historyWithoutSent.historyWithoutSent and save it as updatedHistory. Add a record of invoice id, due date, reminder stage, and flagged stage to the end of historyWithoutSent and save it as updatedHistory.recordErrorIf a step below fails, save the error as recordErrorTry
updatedHistory.Set the stored value 'invoice_reminder_history' to updatedHistory.On error
firstInvoice.CustomerRef.name (invoiceRef) was sent, but Lodol couldn't record it (recordError.message), so the run stopped there rather than send any more. Reminders sent before it are recorded and won't repeat, but the next run has no record of this one, so firstInvoice.CustomerRef.name will get it a second time.Stop and report a problem: The reminder to firstInvoice.CustomerRef.name (invoiceRef) was sent, but Lodol couldn't record it (recordError.message), so the run stopped there rather than send any more. Reminders sent before it are recorded and won't repeat, but the next run has no record of this one, so firstInvoice.CustomerRef.name will get it a second time.No
reminderStage to the end of sampledStages and save it as sampledStages.Add reminderStage to the end of sampledStages and save it as sampledStages.sampleAttachments and invoicePdfs into one list and save it as sampleAttachments.Combine sampleAttachments and invoicePdfs into one list and save it as sampleAttachments.reminderStage in a table and save it as sampleName.Look up reminderStage in a table and save it as sampleName.sampleName, as firstInvoice.CustomerRef.name would receive it (its invoice is attached to this email)
To: sendTo
Subject: emailSubject
reminderBody to the end of examples and save it as examples.No
No steps
chasedInvoice in customer.items:For each chasedInvoice in customer.items:chasedInvoice.stage_reached in a table and save it as stageName.Look up chasedInvoice.stage_reached in a table and save it as stageName.chasedInvoice.summary_line, stageName@sentVerb@sendTo to the end of chasedLines and save it as chasedLines.Add chasedInvoice.summary_line, stageName@sentVerb@sendTo to the end of chasedLines and save it as chasedLines.chasedCount.Add 1 to chasedCount.liveMode is yesIf liveMode is yesYes
tidyErrorIf a step below fails, save the error as tidyErrorTry
updatedHistory.Set the stored value 'invoice_reminder_history' to updatedHistory.On error
tidyError.message). Nothing will be sent twice, but some notes in this summary may appear again next time. to the end of problems and save it as problems.Add • Couldn't update the record of reminders sent (tidyError.message). Nothing will be sent twice, but some notes in this summary may appear again next time. to the end of problems and save it as problems.No
No steps
overdueNow and save it as overdueCount.Count the items in overdueNow and save it as overdueCount.overdueCount is 0If overdueCount is 0Yes
No
No steps
overdueNow by currency, with the total balance of each and save it as currencyTotals.Group the items in overdueNow by currency, with the total balance of each and save it as currencyTotals.totalParts to an empty list.Set totalParts to an empty list.currencyGroup in currencyTotals:For each currencyGroup in currencyTotals:totalStyle to thousands.Set totalStyle to thousands.currencyGroup.key is 3If the length of currencyGroup.key is 3Yes
totalStyle to currency.Change totalStyle to currency.No
No steps
currencyGroup.total as a number and save it as groupTotalText.Format currencyGroup.total as a number and save it as groupTotalText.groupTotalText to the end of totalParts and save it as totalParts.Add groupTotalText to the end of totalParts and save it as totalParts.totalParts with and and save it as totalsText.Join totalParts with and and save it as totalsText.overdueWord to invoices.Set overdueWord to invoices.overdueCount is 1If overdueCount is 1Yes
overdueWord to invoice.Change overdueWord to invoice.No
No steps
problems and noEmailLines into one list and save it as attentionLines.Combine problems and noEmailLines into one list and save it as attentionLines.chasedCount is 0 and the length of attentionLines is 0 is yesIf chasedCount is 0 and the length of attentionLines is 0 is yesYes
overdueCount overdueWord, totalsText in all. Each will be chased when it reaches its next reminder.Finish the run: No reminders were due this morning. Still overdue: overdueCount overdueWord, totalsText in all. Each will be chased when it reaches its next reminder.No
No steps
chasedWord to invoices.Set chasedWord to invoices.chasedCount is 1If chasedCount is 1Yes
chasedWord to invoice.Change chasedWord to invoice.No
No steps
chasedPart to Preview: no reminders due.Set chasedPart to Preview: no reminders due.liveMode is yes and chasedCount is greater than 0If liveMode is yes and chasedCount is greater than 0Yes
Chased @chasedCount @chasedWord and save it as chasedPart.Build the text Chased @chasedCount @chasedWord and save it as chasedPart.Else if @liveMode is yes
chasedPart to No reminders sent.Change chasedPart to No reminders sent.Else if @chasedCount is greater than 0
Preview: @chasedCount @chasedWord ready to chase and save it as chasedPart.Build the text Preview: @chasedCount @chasedWord ready to chase and save it as chasedPart.Otherwise
No steps
@chasedPart · @totalsText overdue across @overdueCount @overdueWord and save it as headline.Build the text @chasedPart · @totalsText overdue across @overdueCount @overdueWord and save it as headline.previewNote to blank.Set previewNote to blank.liveMode is noIf liveMode is noYes
previewNote to:Change previewNote to:This is a preview: nothing has been sent to your customers. Below is what would have gone out this morning, with each kind of reminder written out in full at the end and its invoice attached to this email. When you're happy with them, set the 'sendToCustomers' step to true and the next run sends them for real.No
No steps
attentionSection to blank.Set attentionSection to blank.attentionLines isn't emptyIf attentionLines isn't emptyYes
attentionLines with a new line and save it as attentionText.Join attentionLines with a new line and save it as attentionText.Needs your attention: @attentionText and save it as attentionSection.Build the text Needs your attention: @attentionText and save it as attentionSection.No
No steps
chasedSection to blank.Set chasedSection to blank.chasedCount is greater than 0If chasedCount is greater than 0Yes
chasedLines with a new line and save it as chasedText.Join chasedLines with a new line and save it as chasedText.chasedHeading to:Set chasedHeading to:Reminders that would go out this morning:liveMode is yesIf liveMode is yesYes
chasedHeading to:Change chasedHeading to:Reminders sent this morning:No
No steps
@chasedHeading@chasedText and save it as chasedSection.Build the text @chasedHeading@chasedText and save it as chasedSection.No
No steps
stillOverdueSection to blank.Set stillOverdueSection to blank.stillOverdueLines isn't emptyIf stillOverdueLines isn't emptyYes
stillOverdueLines with a new line and save it as stillOverdueText.Join stillOverdueLines with a new line and save it as stillOverdueText.Still overdue: @stillOverdueText and save it as stillOverdueSection.Build the text Still overdue: @stillOverdueText and save it as stillOverdueSection.No
No steps
examples with a blank line and save it as examplesText.Join examples with a blank line and save it as examplesText.summaryErrorIf a step below fails, save the error as summaryErrorTry
summaryEmail.Send an email to summaryEmail.
Subject: headlineheadline
previewNote@attentionSection@chasedSection@stillOverdueSection@examplesTextOn error
summaryEmail (summaryError.message). to the end of problems and save it as problems.Add • The summary email couldn't be sent to summaryEmail (summaryError.message). to the end of problems and save it as problems.problems isn't emptyIf problems isn't emptyYes
problems with a new line and save it as problemText.Join problems with a new line and save it as problemText.headline. Not everything went through:Stop and report a problem: headline. Not everything went through:
problemText.No
No steps
headline. The summary went to summaryEmail.Finish the run: headline. The summary went to summaryEmail.