This is a cross-platform text-based offline mail reader for the QWK packet format. The QWK packet format was/is often used to exchange mail on bulletin board systems.
SlyMail provides a full-featured interface for reading and replying to messages from BBS (Bulletin Board System) QWK mail packets. Its user interface is inspired by Digital Distortion Message Reader (DDMsgReader) for message reading and SlyEdit for message editing, both originally created for Synchronet BBS.
SlyMail was created with the help of Claude AI.
- Opens and reads standard QWK mail packets (.qwk files)
- Parses CONTROL.DAT, MESSAGES.DAT, and NDX index files
- Full QWKE (extended QWK) support via HEADERS.DAT — offset-based matching for accurate extended To/From/Subject fields, UTF-8 flag, and RFC822 Message-ID
- QWKE body kludge parsing (
To:,From:,Subject:at message start) - Handles Synchronet-style conference numbering
- Creates REP reply packets (.rep files) for uploading back to the BBS, including HEADERS.DAT for extended fields and VOTING.DAT for pending votes
- Supports Microsoft Binary Format (MBF) float encoding in NDX files
- Remembers last opened QWK file and directory between sessions
- Conference list with message counts
- Scrollable message list with lightbar navigation
- Full message reader with header display (From, To, Subject, Date)
- Quote line highlighting (supports multi-level quoting)
- Kludge line display (optional)
- Scrollbar indicator
- Keyboard navigation: First/Last/Next/Previous message, Page Up/Down
- Help screens accessible with
?orF1in all views
SlyMail interprets color/attribute codes from multiple BBS software packages, rendering them as colored text in both the message reader and the message editor. Supported formats:
- ANSI escape codes — always enabled; standard SGR sequences (ESC[...m) for foreground, background, bold
- Synchronet Ctrl-A codes —
\x01+ attribute character (e.g.,\x01cfor cyan,\x01hfor bright) - WWIV heart codes —
\x03+ digit 0–9 - PCBoard/Wildcat @X codes —
@X##where the two hex digits encode background and foreground color - Celerity pipe codes —
|+ letter (e.g.,|cfor cyan,|Wfor bright white) - Renegade pipe codes —
|+ two-digit number 00–31
Each BBS code type can be individually enabled or disabled via the Attribute code toggles sub-dialog in Reader Settings or the config utility. These toggles affect both the reader and the editor. A separate Strip ANSI codes option removes all ANSI sequences from messages when enabled.
- Detects file attachments referenced via
@ATTACH:kludge lines in message bodies - Shows an [ATT] indicator in the message header when attachments are present
- Press D or Ctrl-D in the reader to download attachments — shows a file list with sizes and prompts for a destination directory
SlyMail supports the Synchronet VOTING.DAT extension for polls and message voting:
- Polls: Messages identified as polls display their answer options with vote counts and percentage bars. Press V to open a ballot dialog where you can toggle answer selections and cast your vote.
- Up/Down votes: For regular (non-poll) messages, press V to up-vote or down-vote. Current vote tallies and score are shown in the message header.
- Vote tallies: The message header displays up-vote/down-vote counts and net score, with an indicator if you have already voted.
- Vote queueing: Votes are queued alongside message replies and written to VOTING.DAT in the REP packet for upload to the BBS.
- Poll browser: Press V from the conference list to browse all polls in the packet.
- Detects UTF-8 content in messages (via HEADERS.DAT
Utf8flag and automatic detection of UTF-8 byte sequences) - Displays UTF-8 characters correctly on compatible terminals
- Shows a [UTF8] indicator in the message header for UTF-8 messages
- Saves new messages with proper encoding
- CP437 to UTF-8 conversion for legacy BBS content
- Sets locale on Linux/macOS/BSD (
setlocale(LC_ALL, "")) and UTF-8 code page on Windows for proper terminal rendering
- Two visual modes: Ice and DCT, each with distinct color schemes and layouts
- Random mode: Randomly selects Ice or DCT on each edit session
- Alternating border colors: Border characters randomly alternate between two theme colors, matching SlyEdit's visual style
- Theme support: Configurable color themes loaded from .ini files
- Full-screen text editor with word wrap
- Quote window for selecting and inserting quoted text (Ctrl-Q to open/close)
- Reply and new message composition
- ESC menu for save, abort, insert/overwrite toggle, and more
- Ctrl-K color picker: Opens a dialog to select foreground and background colors, inserting an ANSI escape code at the cursor position. Supports 16 foreground colors (8 normal + 8 bright) and 8 backgrounds, with a live preview. Press N to insert a reset code.
- Color-aware rendering: The edit area renders ANSI and BBS attribute codes inline, so colored text is displayed as you type
- Ctrl-U user settings dialog for configuring editor preferences on the fly
- Style-specific yes/no prompts: Ice mode uses a bottom-of-screen inline prompt; DCT mode uses a centered dialog box with themed colors
- Choose UI mode: Dialog to switch between Ice, DCT, and Random styles (takes effect immediately)
- Select theme file: Choose from available Ice or DCT color themes
- Taglines: When enabled, prompts for tagline selection on save (from
tagline_files/taglines.txt) - Spell-check dictionary/dictionaries: Select which dictionaries to use
- Prompt for spell checker on save: When enabled, offers to spell-check before saving
- Wrap quote lines to terminal width: Word-wrap quoted lines
- Quote with author's initials: Prepend quote lines with the author's initials (e.g.,
MP>) - Indent quote lines containing initials: Add leading space before initials (e.g.,
MP>) - Trim spaces from quote lines: Strip leading whitespace from quoted text
- Theme files are configuration files (
.ini) in theconfig_files/directory - Ice themes:
EditorIceColors_*.ini(BlueIce, EmeraldCity, FieryInferno, etc.) - DCT themes:
EditorDCTColors_*.ini(Default, Default-Modified, Midnight) - Theme colors use a simple format: foreground letter (
r/g/b/c/y/m/w/k), optionalhfor bright, optional background digit (0-7) - Themes control all UI element colors: borders, labels, values, quote window, help bar, yes/no dialogs
- Built-in spell checker using plain-text dictionary files
- Ships with English dictionaries (en, en-US, en-GB, en-AU, en-CA supplements)
- Interactive correction dialog: Replace, Skip, or Quit
- Dictionary files stored in the
dictionary_files/directory
- Tagline files are stored in the
tagline_files/directory - The default tagline file is
tagline_files/taglines.txt, one tagline per line - Lines starting with
#or;are treated as comments and ignored - Select a specific tagline or choose one at random when saving a message
- Taglines are appended to messages with a
...prefix
- Currently, only ZIP is supported (I want to add support for more compression types in the future)
- When you write replies or new messages, they are queued as pending
- Votes (poll ballots, up/down votes) are also queued alongside replies
- On exit (or when opening a new QWK file), SlyMail prompts to save all pending items
- Creates a standard
.repfile (ZIP archive) for uploading to the BBS, containing:<BBSID>.MSG— reply messages in standard QWK formatHEADERS.DAT— QWKE extended headers for fields exceeding 25 charactersVOTING.DAT— pending votes in Synchronet-compatible INI format
- REP file is saved as
<BBS-ID>.repin the configured reply directory (or the QWK file's directory)
SlyMail can download QWK packets directly from remote systems via FTP or SFTP (SSH):
- Press Ctrl-R from the file browser to open the remote systems directory
- Add/Edit/Delete remote system entries with: name, host, port, connection type (FTP or SSH), username, password, passive FTP toggle, and initial remote path
- Browse remote directories with a file/directory browser similar to the local file browser — navigate into directories, go up with
.., jump to root with/ - Download QWK files from the remote system directly into the
QWKsubdirectory of the SlyMail data directory - Remote system entries are persisted to
remote_systems.jsonin the SlyMail data directory - Last connection date/time is tracked for each system
- Uses the system's
curlcommand for FTP and SFTP transfers (no compile-time library dependencies)
- Persistent settings saved to
slymail.iniin the SlyMail data directory (~/.slymailon Linux/macOS/BSD, or the user's home directory on Windows) - The SlyMail data directory and its
QWKsubdirectory are created automatically on first run - Default QWK file browse and REP packet save directory is
~/.slymail/QWK - Remembers last browsed directory and QWK filename
- Ctrl-L hotkey to load a different QWK file from conference or message list views
- Configurable quote prefix, quote line width, user name
- Reader options: show/hide kludge lines, tear/origin lines, scrollbar, strip ANSI codes
- Per-BBS attribute code toggles (Synchronet, WWIV, Celerity, Renegade, PCBoard/Wildcat) — affect both reader and editor
- REP packet output directory
On a Synchronet BBS, in the QWK packet settings, Slymail is (or should be) compatible with Ctrl-A color codes, VOTING.DAT, file attachments, and the QWKE packet format. Slymail should also be compatible with UTF-8. For instance:
<<<<<<<<<<<<<<<<<| Ctrl-A Color Codes | Leave in |
| Archive Type | ZIP |
| Include E-Mail Messages | Un-Read Only |
| Include File Attachments | Yes |
| Delete E-mail Automatically | No |
| Include New Files List | Yes |
| Include Index Files | Yes |
| Include Control Files | Yes |
| Include VOTING.DAT File | Yes |
| Include HEADERS.DAT File | Yes |
| Include Messages from You | No |
| Include Time Zone (@TZ) | No |
| Include Message Path (@VIA) | No |
| Include Message/Reply IDs | No |
| Include UTF-8 Characters | Yes |
| MIME-encoded Message Text | No |
| Extended (QWKE) Packet Format | Yes |
Linux / macOS / BSD:
- C++17 compatible compiler (GCC 8+, Clang 7+)
- ncurses development library (
libncurses-devon Debian/Ubuntu,ncurses-develon Fedora/RHEL) unzipcommand (for extracting QWK packets)zipcommand (for creating REP packets)curlcommand (for remote system FTP/SFTP transfers — optional, only needed for the remote systems feature)
Windows (Visual Studio 2022):
- Visual Studio 2022 with the "Desktop development with C++" workload
- Windows SDK 10.0 (included with VS)
- No additional libraries required — uses the built-in Win32 Console API for the terminal UI, and either
tar.exeor PowerShell for QWK/REP packet ZIP handling (see note below)
Windows (MinGW/MSYS2):
- MinGW-w64 or MSYS2 with GCC (C++17 support)
- Windows Console API (built-in)
Note — QWK/REP ZIP handling on Windows: SlyMail detects at runtime which tool is available and uses the best option:
tar.exe(preferred): Ships with Windows 10 version 1803 (April 2018 Update) and later, and with all versions of Windows 11.tarreads ZIP files by their content rather than their file extension, so.qwkpackets extract directly and.reppackets are created via a temporary.zipfile that is then renamed. No extra configuration is needed.- PowerShell (fallback): If
tar.exeis not found in the PATH, SlyMail falls back to PowerShell. For extraction it uses the .NETZipFileclass (System.IO.Compression) rather thanExpand-Archive, becauseExpand-Archiverejects non-.zipfile extensions even when the file is a valid ZIP archive. For REP packet creation it usesCompress-Archive, again writing to a temporary.zipfile that is then renamed to.rep.
makeThis builds two programs:
slymail- the main QWK reader applicationconfig- the standalone configuration utility
make debugsudo make install # Installs slymail and config to /usr/local/bin/
sudo make uninstall # RemoveOpen the solution file in Visual Studio 2022:
vs\SlyMail.sln
Or build from the command line using MSBuild:
# Release build (output in vs\x64\Release\)
msbuild vs\SlyMail.sln /p:Configuration=Release /p:Platform=x64
# Debug build (output in vs\x64\Debug\)
msbuild vs\SlyMail.sln /p:Configuration=Debug /p:Platform=x64This builds two executables:
x64\Release\slymail.exe— the main QWK readerx64\Release\config.exe— the standalone configuration utility
The solution contains two projects (SlyMail.vcxproj and Config.vcxproj) targeting x64, C++17, with the MSVC v143 toolset.
makeThe Makefile automatically detects the platform and uses the appropriate terminal implementation:
- Linux/macOS/BSD: ncurses (
terminal_ncurses.cpp) - Windows: conio + Win32 Console API (
terminal_win32.cpp)
# Launch SlyMail with file browser
./slymail
# Open a specific QWK packet
./slymail MYBBS.qwk
# Run the standalone configuration utility
./configThe config utility provides a standalone text-based interface for configuring SlyMail settings without opening the main application. It offers four configuration categories:
- Editor Settings - All the same settings available via Ctrl-U in the editor (editor style, taglines, spell-check, quoting options, etc.)
- Reader Settings - Toggle kludge lines, tear lines, scrollbar, ANSI stripping, lightbar mode, reverse order, and attribute code toggles (per-BBS enable/disable)
- Theme Settings - Select Ice and DCT color theme files from the
config_files/directory - General Settings - Set your name for replies and the REP packet output directory
Settings are saved automatically when exiting each category. Both SlyMail and the config utility read and write the same settings file.
| Key | Action |
|---|---|
| Up/Down | Navigate files and directories |
| Enter | Open directory / Select QWK file |
| Ctrl-R | Open remote systems directory |
| Q / ESC | Quit |
| Key | Action |
|---|---|
| Up/Down | Navigate conferences |
| Enter | Open selected conference |
| V | View polls/votes in packet |
| O / Ctrl-L | Open a different QWK file |
| S / Ctrl-U | Settings |
| Q / ESC | Quit SlyMail |
| ? / F1 | Help |
| Key | Action |
|---|---|
| Up/Down | Navigate messages |
| Enter / R | Read selected message |
| N | Write a new message |
| G | Go to message number |
| Ctrl-L | Open a different QWK file |
| S / Ctrl-U | Settings |
| C / ESC | Back to conference list |
| Q | Quit |
| ? / F1 | Help |
| Key | Action |
|---|---|
| Up/Down | Scroll message |
| Left/Right | Previous / Next message |
| F / L | First / Last message |
| R | Reply to message |
| V | Vote (up/down vote or poll ballot) |
| D / Ctrl-D | Download file attachments |
| H | Show message header information |
| S / Ctrl-U | Settings |
| C / Q / ESC | Back to message list |
| ? / F1 | Help |
| Key | Action |
|---|---|
| ESC | Editor menu (Save, Abort, etc.) |
| Ctrl-U | User settings dialog |
| Ctrl-Q | Open/close quote window |
| Ctrl-K | Color picker (insert ANSI color code at cursor) |
| Ctrl-G | Insert graphic (CP437) character by code |
| Ctrl-W | Word/text search |
| Ctrl-S | Change subject |
| Ctrl-D | Delete current line |
| Ctrl-Z | Save message |
| Ctrl-A | Abort message |
| F1 | Help screen |
| Insert | Toggle Insert/Overwrite mode |
| Key | Action |
|---|---|
| Up/Down | Navigate quote lines |
| Enter | Insert selected quote line |
| Ctrl-Q / ESC | Close quote window |
SlyMail uses a platform abstraction layer for its text user interface:
ITerminal (abstract base class)
├── NCursesTerminal (Linux/macOS/BSD - ncurses)
└── Win32Terminal (Windows - conio + Win32 Console API)
CP437 box-drawing and special characters are defined in cp437defs.h and rendered through the putCP437() method, which maps CP437 codes to platform-native equivalents (ACS characters on ncurses, direct CP437 bytes on Windows).
| File | Description |
|---|---|
terminal.h |
Abstract ITerminal interface, key/color constants, factory |
terminal_ncurses.cpp |
ncurses implementation with CP437-to-ACS mapping |
terminal_win32.cpp |
Windows Console API + conio implementation |
cp437defs.h |
IBM Code Page 437 character definitions |
colors.h |
Color scheme definitions (Ice, DCT, reader, list) |
theme.h |
Theme config file parser (Synchronet-style attribute codes) |
ui_common.h |
Shared UI helpers (dialogs, text input, scrollbar, etc.) |
qwk.h / qwk.cpp |
QWK/REP packet parser and creator (QWKE, attachments, voting) |
bbs_colors.h / bbs_colors.cpp |
BBS color/attribute code parser (ANSI, Synchronet, WWIV, PCBoard, Celerity, Renegade) |
utf8_util.h / utf8_util.cpp |
UTF-8 utilities (validation, display width, CP437-to-UTF-8 conversion) |
voting.h / voting.cpp |
VOTING.DAT parser, vote tallying, poll display UI |
remote_systems.h / remote_systems.cpp |
Remote systems directory, FTP/SFTP browsing, JSON persistence, home dir utilities |
settings.h |
User settings persistence |
settings_dialog.h |
Settings dialogs (editor, reader, attribute code toggles) |
file_browser.h |
QWK file browser and selector |
msg_list.h |
Conference and message list views |
msg_reader.h |
Message reader (DDMsgReader-style) with voting and attachment UI |
msg_editor.h |
Message editor (SlyEdit Ice/DCT-style) with color picker |
main.cpp |
SlyMail application entry point and main loop |
config.cpp |
Standalone configuration utility |
Settings are stored in an INI file named slymail.ini in the same directory as the SlyMail executable. This file is shared between both SlyMail and the config utility. The file is well-commented with descriptions of each setting.
Example slymail.ini:
[Editor]
; Editor style for writing messages: Ice, Dct, or Random
editorStyle=Ice
; Enable tagline insertion when saving a message
taglines=false
; Prompt the user to run the spell checker when saving a message
promptSpellCheck=false
[Reader]
; Show kludge/control lines (@MSGID, @REPLY, etc.) in the message reader
showKludgeLines=false
; Strip ANSI escape codes from message text
stripAnsi=false
; Attribute code toggles (affect both reader and editor)
attrSynchronet=true
attrWWIV=true
attrCelerity=true
attrRenegade=true
attrPCBoard=true
[Themes]
; Color theme file for the editor in Ice mode
iceThemeFile=EditorIceColors_BlueIce.ini
; Color theme file for the editor in DCT mode
dctThemeFile=EditorDCTColors_Default.iniColor themes are .ini files in the config_files/ directory:
Ice themes (EditorIceColors_*.ini):
- BlueIce (default), EmeraldCity, FieryInferno, Fire-N-Ice, GeneralClean, GenericBlue, PurpleHaze, ShadesOfGrey
DCT themes (EditorDCTColors_*.ini):
- Default (default), Default-Modified, Midnight
Theme color values use a compact format derived from Synchronet attribute codes:
n= normal (reset)- Foreground:
k=black,r=red,g=green,y=yellow,b=blue,m=magenta,c=cyan,w=white h= high/bright intensity- Background digit:
0=black,1=red,2=green,3=brown,4=blue,5=magenta,6=cyan,7=light gray
Example: nbh = normal blue bright, n4wh = bright white on blue background
Taglines are short quotes or sayings appended to the end of messages when saved. The tagline feature can be enabled via Ctrl-U in the editor or the config utility.
Taglines are stored in tagline_files/taglines.txt, one per line. Lines starting with # or ; are treated as comments and ignored. When saving a message with taglines enabled, the user is prompted to either select a specific tagline or choose one at random. Selected taglines are appended to the message with a ... prefix (e.g., ...To err is human, to really foul things up requires a computer.).
SlyMail includes a built-in spell checker that uses plain-text dictionary files. The spell checker can be configured to prompt on save via Ctrl-U in the editor or the config utility.
Dictionary files are plain text files (one word per line) stored in dictionary_files/. Multiple dictionaries can be selected simultaneously for combined word coverage. SlyMail ships with:
dictionary_en.txt- English (general, ~130K words)dictionary_en-US-supplemental.txt- US English supplementdictionary_en-GB-supplemental.txt- British English supplementdictionary_en-AU-supplemental.txt- Australian English supplementdictionary_en-CA-supplemental.txt- Canadian English supplement
When spell-checking is triggered, the checker scans the message for misspelled words and presents an interactive dialog for each one, offering options to Replace the word, Skip it, Add it (future), or Quit checking.
- UI inspired by DDMsgReader and SlyEdit by Nightfox (Eric Oulashin)
- QWK format compatibility informed by Synchronet BBS source code
- CP437 character definitions from Synchronet
This project is open source software.

















