# Postmortem: VBA Mail Lookup Failure Due to Unset Object Reference
**Summary**
A VBA automation script failed to attach Outlook email items when searching in secondary columns. The code successfully attached emails when matching IDs in Excel's Column C, but threw "Object variable or With block variable not set" errors during fallback searches in Column F, causing incomplete email attachments.
**Root Cause**
The loop iterator variable (`mailItem`) becomes unset after exiting the `For Each mailItem` loop prematurely via `Exit For`:
- After exiting the loop (when Column C finds a match), `mailItem` loses its reference
- Subsequent Column F logic attempts to reuse the invalid `mailItem` reference
- The invalid reference triggers Runtime Error 91 when accessing `mailItem.Subject`
**Why This Happens in Real Systems**
- **Iterator lifetime issues**: Loop variables aren't preserved after early loop exits in VBA
- **Conditional branching**: Fallback logic paths often reference out-of-scope objects
- **Implicit state assumptions**: Code assumes iterators remain valid across multiple search phases
- **Production vs development data differences**: Secondary columns (like Column F) might not get tested thoroughly if primary column tests always succeed during development
**Real-World Impact**
- **Partial execution**: Only primary column matches (Column C) attach successfully
- **Manual intervention**: Script requires user interaction for every missing secondary match
- **Process blocking**: Failure halts entire workflow until resolved
- **Data loss risk**: Secondary matches get silently skipped without attaching
**Example** or Code
**Problematic Code Snippet:**
```vba
For Each mailItem In subFolder.Items
If InStr(1, mailItem.Subject, cell.Value, vbTextCompare) > 0 Then
newEmail.Attachments.Add mailItem, olEmbeddeditem
matchFound = True
Exit For ' mailItem becomes invalid here
End If
Next mailItem
If Not matchFound Then
' mailItem is now NOTHING when Column F check runs:
If InStr(1, mailItem.Subject, cell.Offset(0, 3).Value, vbTextCompare) > 0 Then
newEmail.Attachments.Add mailItem, olEmbeddeditem
Fixed Implementation:
Dim foundMail As Object ' Dedicated mail holder
For Each mailItem In subFolder.Items
If InStr(1, mailItem.Subject, cell.Value, vbTextCompare) > 0 Or _
InStr(1, mailItem.Subject, cell.Offset(0, 3).Value, vbTextCompare) > 0 Then
Set foundMail = mailItem
matchFound = True
Exit For
End If
Next mailItem
If matchFound Then
newEmail.Attachments.Add foundMail, olEmbeddeditem
End If
How Senior Engineers Fix It
- Decouple objects from iterators: Create persistent reference holders (
Set foundMail = mailItem) - Consolidate search logic: Combine search criteria in single loop instead of sequential searches
- Validate object states: Add guard clauses like
If foundMail Is Nothing Thenbefore use - Extract helper functions: Separate mail searching into distinct methods with proper scoping
- Refactor fallbacks: Replace sequential searches with unified pattern matching
- Add error boundaries: Implement
On Error Resume Next+ validation around attachment operations
Why Juniors Miss It
- Scope misunderstanding: Underestimating iterator variable lifetime outside loops
- Over-reliance on happy paths: Testing only with Column C data never exposes Column F failure
- Debugger dependence: Assuming debug mode preserves object states differently than runtime
- Error handling gaps: Not anticipating MS Office COM object quirks
- Code structure blindness: Focusing on core functionality over branch condition states
- Assumption bias: Believing “Exit For” preserves current loop variable state