vba.blacktorgroup.com/Resilient Export

Making the nightly close-out macro survive a missing network drive.

Ride Me Cycles' nightly close-out macro saved a PDF to a network drive and emailed it through Outlook, both of which occasionally weren't ready yet when the macro ran unattended overnight. A retry loop keeps it running instead of leaving the close-out undone until someone notices in the morning.

A translucent black cube etched with a moss-green map of the world's continents, glowing softly against black.
BlackTor Group Ltd Dartmoor, UK
A note on this page

A reference, not a client write-up.

Illustrative, per the note on the main VBA page: not real client work. It sits alongside the Frame-Number Check and Warranty Claims pages as a deeper dive on one routine that comes up often enough to be worth its own write-up.

The issue

A resource that's usually there isn't always there at midnight.

The macro runs unattended overnight, straight after the machine wakes on a schedule. A few seconds after waking, the network drive isn't always reconnected yet, and Outlook isn't always fully started. Both are almost always ready within moments, but the macro as originally written failed outright the instant either one wasn't ready at that exact moment, leaving the whole close-out undone.

The fix isn't more error handling around a single attempt, it's giving the same attempt a few more chances, a short pause apart, before actually giving up.

Retry with backoff

RunNightlyCloseOut: retry a transient failure instead of giving up on the first one

Option Explicit ' RunNightlyCloseOut ' ------------------ ' Saves the day's close-out pack as a PDF to the shared drive and emails ' it, retrying each attempt on failure instead of giving up outright: ' both the network drive and Outlook can be transiently unavailable a ' few seconds after the scheduled task wakes the machine, and are ' almost always back within the time this loop allows. Private Const MAX_RETRY_ATTEMPTS As Integer = 5 Private Const RETRY_DELAY_SECONDS As Integer = 10 Public Sub RunNightlyCloseOut() Dim strPdfPath As String strPdfPath = "\\FILESERVER\CloseOut\CloseOut-" & Format(Date, "yyyymmdd") & ".pdf" If Not TryWithRetry(strPdfPath) Then LogFailure "Close-out pack could not be saved or sent after " & _ MAX_RETRY_ATTEMPTS & " attempts." End If End Sub Private Function TryWithRetry(ByVal strPdfPath As String) As Boolean Dim intAttempt As Integer For intAttempt = 1 To MAX_RETRY_ATTEMPTS If SaveAndEmailCloseOut(strPdfPath) Then TryWithRetry = True Exit Function End If ' A short wait gives a reconnecting network drive or a still- ' starting Outlook instance time to come up before the next ' attempt, rather than hammering a resource that isn't ready yet. Application.Wait Now + TimeSerial(0, 0, RETRY_DELAY_SECONDS) Next intAttempt TryWithRetry = False End Function Private Function SaveAndEmailCloseOut(ByVal strPdfPath As String) As Boolean On Error GoTo HandleFailure ThisWorkbook.Worksheets("Close-Out Pack").ExportAsFixedFormat _ Type:=xlTypePDF, Filename:=strPdfPath, Quality:=xlQualityStandard Dim objOlApp As Object Dim objOlMail As Object Set objOlApp = CreateObject("Outlook.Application") Set objOlMail = objOlApp.CreateItem(0) ' 0 = olMailItem With objOlMail .To = "enquiries@blacktorgroup.com" .Subject = "Close-out pack, " & Format(Date, "dd mmmm yyyy") .Body = "Attached: tonights close-out pack, generated automatically." .Attachments.Add strPdfPath .Send End With SaveAndEmailCloseOut = True Exit Function HandleFailure: SaveAndEmailCloseOut = False ' let TryWithRetry decide whether to try again Set objOlMail = Nothing Set objOlApp = Nothing End Function Private Sub LogFailure(ByVal strMessage As String) Dim intFileNumber As Integer intFileNumber = FreeFile Open "\\FILESERVER\CloseOut\failure-log.txt" For Append As #intFileNumber Print #intFileNumber, Format(Now, "yyyy-mm-dd hh:nn:ss") & " -- " & strMessage Close #intFileNumber End Sub

SaveAndEmailCloseOut reports success or failure through its return value rather than letting an error propagate and stop the routine, which is what lets TryWithRetry decide what happens next instead of the macro simply ending. This is the same discipline the main VBA page's error-handling note describes: every error branch cleans up its own objects before returning, so a failed attempt never leaves an Outlook object half-built behind it.

The wait between attempts only happens after a failure, not before the first attempt, so the routine loses no time at all on a normal night when everything is ready first time.

LogFailure exists because nobody is watching a macro that runs at midnight: if every attempt genuinely fails, the routine still needs to leave a record somewhere a person will actually look the next morning, rather than failing silently a second time.

Result

A brief delay most nights beats a missed close-out most weeks.

The close-out pack now reliably saves and sends even when the network drive or Outlook take a few extra seconds to be ready, and a genuine failure leaves a clear record instead of an empty inbox nobody notices until it's asked about.