--list bypasses delay threshold and shows all MIDs sorted by start time with Status column always visible. --filter / -f narrows by status: done, aborted, pending, delayed.
ESA-Script
Utility scripts for analyzing Cisco Email Security Appliance (ESA) mail gateway log files.
Requirements
- Python 3.8+
- No external dependencies — standard library only
Log File Format
ESA mail logs follow the naming pattern:
mail.current # active log (rotated periodically)
mail.@20260303T005159.s # archived log with timestamp
Scripts
mid_delay.py
Parses ESA mail logs and reports MIDs (Message IDs) whose delivery took longer than a specified threshold. Results are sorted by delay, longest first.
Basic Usage
python3 mid_delay.py mail.current
python3 mid_delay.py mail.@20260303T005159.s
python3 mid_delay.py mail* # multiple files via shell glob
Options
| Option | Short | Default | Description |
|---|---|---|---|
--threshold |
-t |
0.5 |
Minimum delay in minutes to report |
--top |
-n |
20 |
Limit number of results shown |
--status |
-s |
(all) | Filter by status category; also shows Status column |
--pending |
off | Show only MIDs still in-queue (no finish event) | |
--no-partial |
off | Exclude MIDs with no Start MID line in this log |
|
--include-aborted |
off | Include MIDs that were aborted (excluded by default) | |
--start |
(none) | Only include MIDs whose start time is on or after this datetime | |
--list |
off | List all MIDs regardless of delay; use --filter to narrow by status |
|
--filter |
-f |
(all) | Filter by status in --list mode: done, aborted, pending, delayed |
Status Categories (--status)
| Value | Description |
|---|---|
delayed |
Had an explicit Delayed: retry event in the log |
slow_done |
No retry event, but start→finish exceeded threshold; delivered successfully |
slow_aborted |
No retry event, but start→finish exceeded threshold; delivery aborted |
all |
All of the above; forces the Status column to appear |
--start Datetime Format
Accepts either:
YYYY-MM-DD— matches from the start of that dayYYYY-MM-DD HH:MM:SS— matches from that exact second
python3 mid_delay.py mail* --start 2026-03-03
python3 mid_delay.py mail* --start "2026-03-03 14:30:00"
List Mode (--list)
Lists every tracked MID sorted by start time, bypassing the delay threshold entirely. The Status column is always shown. Use --filter / -f to narrow results by status.
| Status | Meaning |
|---|---|
done |
Delivered successfully, no retry event |
aborted |
Delivery aborted |
pending |
No finish event found in the log |
delayed |
Had at least one Delayed: retry event |
# List all MIDs
python3 mid_delay.py mail.current --list
# List only pending MIDs
python3 mid_delay.py mail* --list -f pending
# List delayed MIDs after a specific time
python3 mid_delay.py mail* --list -f delayed --start "2026-03-03 12:00:00"
Output Columns
MID Start End/Delayed Delay(m) Reason
- MID — Message ID
- Start — Time of
Start MIDevent. Marked with*if the originalStart MIDline was not found in the parsed log(s) and aDelivery startevent was used as a fallback — delay figures for these may be unreliable. - End/Delayed — Time of
Message finishedevent, or firstDelayed:retry event if still pending - Delay(m) — Delay in minutes
- Status — Always shown in
--listmode; shown in delay mode when--statusis specified - Reason — First delay reason or abort reason found for the MID
Multi-File Parsing
When multiple files are provided (e.g. mail*), they are processed in sorted order so that archived logs (mail.@...) are parsed before mail.current. All files share a single MID tracking table, so a message that starts in one file and finishes in another is tracked correctly.
python3 mid_delay.py mail*
python3 mid_delay.py mail.@20260101T000000.s mail.@20260201T000000.s mail.current
Examples
# Default: top 20 delayed MIDs, threshold 0.5 min, aborted excluded
python3 mid_delay.py mail.current
# Top 50 MIDs delayed more than 5 minutes across all log files
python3 mid_delay.py mail* -t 5 -n 50
# Only MIDs with explicit retry events, show Status column
python3 mid_delay.py mail.current -s delayed
# MIDs still pending delivery (never finished in this log)
python3 mid_delay.py mail.current --pending -t 0
# Exclude MIDs without a Start MID line (carried over from prior log)
python3 mid_delay.py mail.current --no-partial
# Include aborted MIDs in results
python3 mid_delay.py mail* --include-aborted
# Only MIDs that started on or after a specific date/time
python3 mid_delay.py mail* --start "2026-03-03 12:00:00"
# Combine filters: slow delivered MIDs after noon, top 10
python3 mid_delay.py mail* -s slow_done --start "2026-03-03 12:00:00" -n 10
# List all MIDs sorted by start time
python3 mid_delay.py mail.current --list
# List only pending MIDs
python3 mid_delay.py mail* --list -f pending
# List delayed MIDs after a specific time
python3 mid_delay.py mail* --list -f delayed --start "2026-03-03 12:00:00"
delay.py
Filters and prints lines containing ERROR from mail.@20260303T005159.s.
python3 delay.py
MID Lifecycle Tracked
Start MID → [Delayed: retry events] → Message finished (done / aborted)
↑
Delivery start (fallback if Start MID not in log)
Events recognized:
| Log Event | Purpose |
|---|---|
Start MID <id> ICID |
Message ingestion start |
Delivery start DCID <d> MID <id> |
Delivery attempt start (fallback start time) |
Delayed: DCID <d> MID <id> ... |
Delivery retry/delay event |
Message finished MID <id> done|aborted |
Final delivery outcome |
Message aborted MID <id> <reason> |
Abort reason capture |
MID <id> rewritten to MID <id> |
MID rewrite tracking |