All detailed versions

01 / 03

dm

Personal messages from a spreadsheet - local, secure, in Hebrew.

Creative Labs · UI/UXMVPPrivate demoProduct thinkingAI-assisted build

The message screen in dm: the file’s columns as field buttons on the side, a message with fields woven in, and a live preview of the first recipient.

A Windows application that sends each person a message of their own from an Excel or CSV file: fields from the file inside the text, wording that changes by condition, a check before sending, and a measured send by e-mail or WhatsApp. All the data stays on the computer.

Note Every name, address and number on the screens is invented; no real data was used. The screens were captured from the application itself on a fresh profile. This is written for development, information systems and management: the product and what it takes to run it first, then the person who built it.

My contribution
Specification, interface and brand design, and direction of the build with Claude Code.
Discipline
Creative Labs · UI/UX
Product state
MVP · Private demo

01

Where it stands

dm is a complete, working application: everything between the file and the send - import, writing, conditions, checking and approval - works and has been tested. What has not been done yet is a test against real accounts, and the step from one person’s tool to something an organisation runs.

  1. Idea
  2. Prototype
  3. Works end to end
  4. Tested on real accounts
  5. Controlled pilot
  6. In daily use

Today: a working tool tested on files and on a simulated send. Next: a trial with a real mailbox and WhatsApp line, agreed with information security.

Works and tested today

  • Import of CSV and XLSX with encoding and delimiter detection, and a type for every column

    Name, phone, e-mail, number, date. A missing value stays missing - it never turns into zero; an invalid one is flagged, not dropped.

  • Writing a message with fields from the file and a live preview

    Plus conditional wording - a different sentence for a woman and a man, say - on a separate tab in plain language.

  • Matching against a distribution list by name, for files that carry no contact details

    Anyone not found is listed separately and can be added, chosen by hand or left out.

  • A review before sending, and an approved send plan that cannot be changed

    What was reviewed is exactly what is sent. Duplicates and clashing destinations are flagged and need a decision - they are never merged quietly.

  • Sending in batches, a safe stop, and resuming where it stopped

    In a simulated run of 150 recipients with a stop in the middle: 150 sent, no duplicates, none missed.

  • Encrypted storage on the computer, and a tool that starts empty on a new machine

    Proven by launching the packaged app on a clean profile: it creates a new machine-bound key and empty folders - no passwords, connections or projects.

Needed to be fully functional

  • A test against a live provider: a real mailbox and a real WhatsApp deviceIS

    So far sending has only been tested against a simulated provider. No real recipient has received a message yet.

  • A decision on how the organisation sends: e-mail through Outlook or the mail server, and an official route for WhatsAppIS

    The current WhatsApp link drives WhatsApp Web and is unofficial; the official route (Cloud API) is set up in the settings but not connected.

  • A digital signature on the installer, and a managed installDev

    The installer is not signed today, so Windows shows a SmartScreen warning. Only Windows 11 is supported.

  • An independent security reviewIS

    The threat model and controls are documented, but no certification is claimed and no outside audit has been done.

  • A controlled trial with a short list and a person approving every sendManagement

What the tests do not cover: sending through a live provider, installing on the organisation’s computers, and performance on very large files. The sentences here rest on the product’s documentation and on running it, not on real use.

02

From the pain to the product

How we got from “everyone needs a different message” to a tool that can be trusted. The telling here is reconstructed from the working process and the documentation.

  1. The pain

    A personal message for every person, by hand

    When each person needs to hear their own numbers or the wording that suits them, someone copies from a spreadsheet row into a message. It is slow, and every copy can go wrong: someone else’s name, an empty number that became “zero”, the wrong grammatical gender. Afterwards there is no record of who got what.

  2. The requirement

    Not a mass mail - a personal send you can check

    Saying the same thing to everyone is easy. The hard part is each person’s values and wording, a check before sending, and real Hebrew. Hence the decisions: local rather than cloud, deterministic algorithms rather than an AI that invents, and an interface in the language of someone who is not a specialist.

  3. The turn

    What was checked is what is sent

    Two principles made the tool trustworthy: typed cells (missing is not zero and not invalid) and an approved send plan that is frozen the moment you approve. Everything else leans on them: the review, the clashes, resuming after a stop.

  4. The connections

    Four ways to send, because no single way fits everyone

    An SMTP server is not always available - many organisations block it. So Outlook, already signed in on the computer, and a Google account were added, and a linked WhatsApp beside them. Each route states what it needs and what its limits are.

  5. The hardening

    Prove it, do not assume it

    A written threat model, encrypted storage, an isolated interface, and a launch of the packaged app on a clean profile to see that it installs with no passwords and no data. And if something was not tested, the status says so plainly.

  6. Today

    A working tool, waiting for a real test

    What remains is not code but decisions: how the organisation sends, who approves, and which list to try first.

03

How it works

Four stages in the interface - import data, connect the message, recipients and rules, review and send - and one flow behind them. At its heart is the approved send plan: from the moment of approval nothing in it changes, and every recipient is sent from it.

  1. In

    A file and a distribution list

    CSV or XLSX. The file is read without running formulas or macros, and every column gets a type.

  2. Step

    A message with fields

    Text, fields from the file and emoji in one flowing line, and a preview for every recipient.

  3. Step

    Conditions

    Different wording when a column’s value matches: the first match wins, and if none does, the ordinary wording.

  4. Step

    Recipients and rules

    Who receives, on which channel, and what the review shows. Phone numbers are normalised; a destination that repeats is flagged.

  5. Kept

    Review and approval

    Every message as it will be sent, with a status for each row. Approval creates a frozen send plan.

  6. Step

    The way it is sent

    Four options, with a measured pace for each. Details in the next section.

    • A mail server (SMTP)E-mail

    • Outlook installed on the computerE-mail

    • A Google accountE-mail

    • A linked WhatsAppMessage

  7. Out

    History and result

    For each recipient: sent, failed or skipped - and why. Acceptance by the provider is not proof of delivery, and the interface says so.

04

How the connections work

The “Connections and settings” screen shows the real state of every route - what is connected, what is only set up, what is switched off - and promises nothing beyond what was built. Here are the four routes and what each one needs.

Mail serverBuilt, needs an account

How it connects
An ordinary connection to the mail provider’s SMTP server: host, port, encryption, user, password. Presets for common providers fill the details in one click.
What it needs
An account that allows SMTP and a dedicated app password. The details are stored encrypted on the computer and used only to connect to the server.
The limit
In many organisations SMTP is blocked outright - which is why there is a second route.
Why it is built this way
A cryptic network error when someone typed an e-mail address into the server field became a validity check and a plain-language explanation.

Outlook on the computerBuilt, needs signed-in Outlook

How it connects
The message is handed to the Outlook that is already signed in to the mailbox on the computer. One helper process lives through the whole send, so Outlook is not reopened for each message; messages reach it as an encoded payload, so quotes or special characters cannot break or inject anything.
What it needs
Outlook installed and signed in. The app never touches a password and never creates one.
Why it exists
When the organisation blocks SMTP, an app password cannot even be created. Outlook is already authenticated against that mailbox - so the message is handed to it.
The limit
Works only on a computer where Outlook is installed and signed in, and only on Windows.

A Google accountBuilt, needs a Google project

How it connects
Sign-in in the computer’s real browser (never an embedded window), an OAuth flow with PKCE and a local listener that receives the redirect. Only a refresh token comes back to the app; the password never passes through it.
What it needs
The organisation’s own Google Cloud project with a desktop OAuth client; until it is verified, a limit on test users.
The limit
The permission required is broad mail access, because authenticated SMTP needs it - a point for information security to review.

WhatsAppWorks, unofficial

How it connects
Linking as a linked device: scan a QR code from the phone, or get a pairing code for the phone number. The session is kept on the computer, so there is no re-linking at every launch, and each destination number is verified before it is sent to.
What it needs
A real WhatsApp device and an internet connection. A real-device test has not been done yet.
Limit and risk
It drives WhatsApp Web, not an official interface: it can break, and it can lead to the account being restricted. That is why the pace is random with long breaks, and why there is an “assisted” mode that prepares a message and leaves the final send to a person.
The official route
The WhatsApp Cloud API: it is set up in the settings (number ID, approved template, variable mapping) but not connected for live sending. This is the route that suits an organisation.

05

A pace that does not look like a machine

A fixed gap between messages is itself a sign of automation. On WhatsApp the pace is random: a gap between 0.6 and 1.8 times the setting, and a long pause after every 10 to 20 messages, whose length is also drawn each time. The pause shows as a countdown, it can be cancelled, and e-mail keeps the fixed pace.

SendingLong pause
One test run of 60 messages at a 4-second setting: three pauses after 17, 13 and 13 messages, lasting 108, 155 and 116 seconds. About 11 minutes in all, against about 4 at a fixed gap - slower by design.
  • 17 messages: 80 seconds
  • 108 s: 108 seconds
  • 13: 61 seconds
  • 155 s: 155 seconds
  • 13: 61 seconds
  • 116 s: 116 seconds
  • 17: 80 seconds

06

From the file to the message

The screens are captures of the application itself, with invented data. Click a screen to scroll inside it.

dm’s home screen: a new project, continue a saved project, distribution lists, connections and settings.
Home: start a project from an existing list or from a file
The data import screen: a table with a detected type for every column, and settings for encoding, delimiter and the default country for phones.
Import: a type for every column, and a warning on a column whose meaning is unclear
A dialog asking whether to match against a distribution list, because the file has no phone or e-mail.
A file without contact details: match it against a distribution list by name
The match review: three names not found in the list, with the option to add, choose by hand or leave out.
Names that were not found do not vanish: each one is decided
Writing the message: fields from the file as chips inside the text, a subject, and a preview for the first recipient in e-mail or WhatsApp.
Writing: fields as chips, and a live preview for every recipient
The conditions tab: version 1 when the language preference equals female and version 2 when it equals male, each with its own text.
Conditions: a different sentence for a woman and a man, without writing a formula

07

From the list to the send

Recipients and rules, the review, and the send screen itself - including a test run on a simulated provider, which can be done before touching a real account.

The recipients and rules stage: how to show the recipients, the send channel, the e-mail and phone columns, and a default label.
Recipients: channel, destination columns and a label for each row
The review before sending: a recipients table with a status, and a warning about one destination clash that needs a decision.
Review: a destination clash is flagged and needs a decision, not swallowed
The send panel: WhatsApp not linked, a recipient who will not get the message because the phone is invalid, sending in batches, and a test run on a simulated provider.
Send: who will not receive and why, batches, and a test run
The result of a test run on a simulated provider: a list of recipients with an accepted status for each.
A test run: each recipient with a status, without sending anything for real
The connections screen: WhatsApp not connected with a link button, e-mail not set up, and further providers marked as setup only or experimental.
Connections: the real state of every provider, including what is only set up
E-mail settings in the Outlook-on-this-computer mode: no password, and a note that sending will be from the signed-in mailbox.
Through Outlook: no password at all
E-mail settings in the Google account mode: the client ID and details of the organisation’s project, and a browser sign-in button.
Through Google: sign-in in the browser, no password in the app

08

Cracks and fixes

Real faults that surfaced on the way, and what turned each from a problem into a feature. Each is recorded in the product’s status notes.

  • The problem

    A missing value in the sheet turned into a message saying “you did 0 hours”.

    The fix

    Typed cells: missing is not zero and not invalid, and the original value is kept. Only one explicit fallback rule accepts a missing value, and if you want a zero you write it.

  • The problem

    A rule for “fewer than 6” and one for “more than 6” quietly drop the person with exactly 6.

    The fix

    The boundary value is handled explicitly and cannot fall between the rules; there is a test for it.

  • The problem

    Two people with the same phone or address, or one person listed twice.

    The fix

    Destination-clash detection: nothing is merged quietly. The review shows the clash and requires a decision before approval.

  • The problem

    In many organisations SMTP is blocked and an app password cannot be created.

    The fix

    Sending through the Outlook already signed in on the computer: no password, and messages reach the helper process as an encoded payload.

  • The problem

    WhatsApp linking crashed at start-up when a stuck browser profile was left from last time.

    The fix

    Stale lock files are cleared, and if start-up still fails the session is wiped and retried once on a fresh profile. A QR code appears instead of a crash.

  • The problem

    WhatsApp reloads its page right after linking, and the message in flight fails.

    The fix

    The app waits for the connected state before each send and retries a send that failed on a momentary frame error, with a growing delay.

  • The problem

    A long list sent in one go cannot be stopped and resumed safely.

    The fix

    Batches: send the next N and decide when each batch starts. A stop in the middle advances the cursor only by what was actually attempted, so the next batch resumes at the first recipient not yet sent.

  • The problem

    An Excel file can carry formulas, macros or hostile content.

    The fix

    The file is read without running anything; values are escaped before they enter an e-mail, and links are allowed only as http or https. The formula reader is hand-written and never runs code from the file.

09

Brand, splash and motion

The interface is built from the logo’s own colours: a deep blue at the top of the bubble, sky at the tail, and cream lettering. Cream is the only warm thing on screen and marks only what is live right now, so it does not lose its meaning. The opening animation is Steve’s, recorded from the application itself.

The opening, about 3 seconds, in a transparent, frameless window
  • Deep blue#2C50A3Top of the bubble, main buttons
  • Mid blue#2E6DB6The accent
  • Sky#359ED8The tail of the bubble
  • Cream#FBDA90Only what is live now
  • Ground#F6F8FBThe app background
  • Ink#1F2937Text

Type

  • Heebo bundled inside the app, nothing loaded from the network (open licence)

Design rules

  • The logo never mirrors in RTL: the bubble’s tail is always in the bottom-right corner.
  • Hebrew first, and a full dark mode with a switch, remembered between launches.
  • Each column type has its own subtle colour, to recognise at a glance.
  • No screen promises more than was built: every provider is shown in its real state.

10

Tools and how they fit

Steve specified, designed and directed; Claude Code wrote and checked according to the decisions. Here are the stages and the tools in each.

  1. 01

    Specify

    The specification in Claude is based on a specification document: requirements in Hebrew, decisions that are written down, and an honest status that marks what was tested and what was not.

    • Claude Codethe specification conversation, based on the specification document, recording decisions
    • Figmawireframes
  2. 02

    Design and brand

    Logo, colours and tokens, and the opening animation.

    • Illustratorcreating the logo
    • After EffectsSteve’s opening animation
    • Lottieplaying the animation inside the app
  3. 03

    Build

    A framework-free core, and a hardened desktop shell.

    • Electronthe desktop application
    • React · Vite · TypeScriptthe interface and the core
    • SheetJS · Papa Parse · libphonenumberreading files and phones
    • nodemailer · whatsapp-web.jssending by e-mail and WhatsApp
    • PowerShellthe Outlook helper process
  4. 04

    Check

    Deterministic tests for the core, and evidence from the packaged app.

    • Vitestimport, rules, rendering, pacing, resume
    • Zodvalidating every message between the interface and the main process
  5. 05

    Package and hand over

    An installer and documents: security, dependencies and licences.

    • electron-builder (NSIS)the Windows installer
    • package-lockreproducible builds

11

What it takes to run for real

The list is split by who has to decide or supply. Nothing in it requires rewriting the product.

Information systems

Decide how the organisation sends, and approve it.

  • A mailbox for the trial, or approval to send through the installed Outlook.
  • A ruling on WhatsApp: the official route (Cloud API) instead of the unofficial link, with a business account and approved templates.
  • A security review, and approval of the dependencies and licences as listed in the product.
  • Approval to install on the organisation’s computers (Windows 11).

Development

Close what is left in the code and the hand-over.

  • Code signing for the installer, and signed version updates.
  • Connecting the WhatsApp Cloud API for live sending, and Microsoft Graph as an alternative to local Outlook.
  • A durable send queue with retries and scheduling (it exists as a data model, not as a complete mechanism).
  • Load tests on very large files.

Management

Define who uses it and how widely.

  • A first list for the trial, and a person who approves every send.
  • A policy: which messages may be sent this way, and to whom.
  • Ownership of the product after the trial: who maintains it, and who takes the requests.