Read X9.37 / X9.100-187 Image Cash Letter (ICL) files on macOS — a free stand-in for Mavro X9 Viewer.
Download the app and open a file — or run it from source, where it uses only the
Python 3 standard library plus macOS's built-in sips. No third-party packages
either way.
Two front ends over the same parser:
x9app.py— the graphical viewer. Structure tree, item grid, check images, record inspector. This is the Mavro-equivalent.x9view.py— the command line, for summaries, dumps, bulk image extraction, and static HTML reports.
Download X9-Viewer.dmg — Apple Silicon, macOS 11 or newer. Nothing else to install; the app carries its own Python.
- Open the .dmg and drag X9 Viewer onto Applications.
- Open it from Applications. macOS refuses the first time — "Apple could not verify this app is free of malware". Click Done, not Move to Trash.
- Go to System Settings → Privacy & Security, scroll to Security, and click Open Anyway next to "X9 Viewer" was blocked to protect your Mac. Confirm, then Open Anyway once more.
- From then on it opens with a normal double-click.
- Click Choose a file… and pick your
.x9/.x937/.iclfile.
Steps 2–4 exist because the app is not signed with a $99/year Apple developer certificate. They are not a finding about the app. On macOS 15 and later Apple removed the old right-click → Open shortcut, so System Settings is the only way through. In a terminal, the whole dance is one command:
xattr -dr com.apple.quarantine "/Applications/X9 Viewer.app"No file you open ever leaves your Mac.
git clone https://github.com/blacknose/x9view.git
cd x9view
python3 x9app.py /path/to/your-file.x937Needs the Python 3 that ships with macOS. Don't have an X9 file handy?
python3 make_sample.py sample.x937 writes one.
./build_app.sh # Apple Silicon (what gets released)
./build_app.sh --universal # also bundles the Intel runtimeIntel is off by default: macOS now posts a "Support Ending for Intel-based Apps" warning about any bundle containing x86_64 code, and carrying it doubles the download.
python3 x9app.py sample.x937It opens in a chromeless Chrome window, so it looks and behaves like a native app rather than a web page. Four panes:
- Structure — file → cash letter → bundle. Click any level to scope the item list to it. Record counts for the whole file sit underneath.
- Items — every check and return, with sequence, routing, on-us, payee, and
amount. Returns are tagged and shown in red. Type
/to jump to the filter, which matches on any of those fields. - Images — front and back on a paper plate. Click either one for full size,
Fliprotates a back image 180°,TIFFdownloads the original bytes. - Inspector — one tab per record belonging to the selected item (25, 26, 50 F, 52 F, 50 B, 52 B …), each showing every field decoded by name.
↑/↓ walk the item list. Other flags: --port N, --tab to use a normal
browser tab, --no-open to just print the URL.
You can also point it at a different file without restarting: type a path into the bar at the top and press Return.
The server binds to 127.0.0.1 only, requires a random per-run token on every
request, and checks the Host header. Since it opens files anywhere on disk by
path, this matters: without it, any web page you had open could quietly ask the
server for the contents of your cash letters.
python3 x9view.py FILE # summary: headers, totals, record counts
python3 x9view.py FILE --dump # decode every record, field by field
python3 x9view.py FILE --dump --limit 0 # ...all records, not just the first 50
python3 x9view.py FILE --images out/ # extract the check images to a folder
python3 x9view.py FILE --html report.html # self-contained HTML viewer--html writes a single self-contained page — every item's amount, MICR
fields, payee, and front/back images inlined as base64 PNGs. Useful for handing
a file to someone who does not have this checked out; for actually working
through a cash letter, use the app.
Useful flags for --html:
--max-items N— render only the first N items (default 200,0for all)--no-convert— skip thesipsconversion; images are listed but not embedded
- Physical layouts: variable-length records with a 4-byte big-endian length prefix, and fixed 80-byte records
- Encodings: EBCDIC (cp037) and ASCII, detected automatically
- Records decoded field by field: 01, 10, 20, 25, 26, 31, 50, 52, 70, 90, 99. Other record types are counted and listed by name.
- Images: TIFF (CCITT G4 and friends), JPEG, PNG. The declared length fields in the type 52 record are used first; if a vendor padded or mangled them, the record is scanned for an image magic number instead.
make_sample.py writes a synthetic EBCDIC file — three checks, one return, and
eight images — so you can exercise every code path without touching real cash
letters:
python3 make_sample.py sample.x937
python3 x9app.py sample.x937X9 files carry full MICR lines, account numbers, payee names, and check images. Keep them local — this tool never sends anything anywhere, which is the main reason to prefer it over the browser-based converters.
