A send-confirmation add-in for new Outlook and Outlook on the web.
It runs when you press Send. Outlook's built-in Smart Alerts dialog opens a review task pane with checkboxes for recipients, attachments, subject, and body. After everything is checked, the review pane sends the message. The goal is to stop the small mistakes: the wrong recipient, the forgotten attachment, the empty subject.
Scheduled send / Send later is not supported. When Outlook has a future delivery time on the draft, Mail Lookout skips its review flow and lets Outlook schedule the message unchanged. Scheduled messages are therefore not checked by this add-in.
The name is literal: a lookout for your outgoing mail — a quiet watch that flags problems before a message leaves.
Japanese version: README.ja.md
Mail Lookout is publicly available on Microsoft Marketplace: get Mail Lookout for Outlook. Open the listing, select Get it now, and follow the Microsoft 365 installation flow. No manifest download or sideloading is required for normal installation.
This add-in does four things at send time.
- Recipient check. It lists every recipient by field (To, Cc, Bcc) and marks external ones.
- Attachment check. It lists every real attachment.
- Body check. It shows a preview of the body and asks you to review it.
- Review pane confirmation. It blocks the first send attempt and opens a task pane where required items must be checked.
It also raises two warnings:
- Empty subject. Requires an explicit check when the subject is blank.
- Forgotten attachment. A warning when the body mentions an attachment ("see attached", "添付") but no file is attached.
A Settings task pane lets each user adjust the internal domains
and the default send-delay. Those are stored per user in Outlook
roaming settings, so they follow the user across devices. Everything
else — and the shipped defaults — lives in one config file,
src/config/defaults.ts.
On Send, Outlook's Smart Alerts opens the review pane; once the checklist is confirmed, a cancellable countdown sends the message.
The review pane in Outlook on the web:
Up close — the review checklist and the send-wait countdown:
The built-in Smart Alerts message that opens the review:
- New Outlook on Windows, or Outlook on the web.
- Mailbox requirement set 1.15 or later.
- Bun 1.3 or later for development.
This add-in does not run on Outlook mobile. See the limitations section for classic Outlook on Windows.
The code is split so the logic does not depend on Office.
src/
domain/ Pure logic. No Office, no DOM, no time. Fully tested.
config/ The config shape and its defaults.
i18n/ Type-safe messages. One file per language.
shared/ Shared message shapes used by the browser-only preview.
office/ The Office adapter. Reads the draft, runs the Smart Alerts handler.
commands/ Registers the send handler with Office.
dialog/ Renders the browser-only confirmation preview.
The domain layer is the core. It takes a plain snapshot of the
message plus the config, and it returns a flat, JSON-serializable
model. It decides what to show and what to require. Because it
touches nothing from the host, every rule is tested with plain
data. The tests are where the value is.
The office layer is a thin adapter. It reads the draft through
the Office APIs, hands a plain snapshot to domain, and then uses
Outlook's built-in Smart Alerts dialog to cancel or allow the send.
The core layers import nothing from Office, so the boundary holds by
construction; keep any new host calls in the office layer.
# 1. Install dependencies.
bun install
# 2. Trust a local HTTPS certificate. Outlook requires HTTPS.
bun run dev-certs
# 3. Start the dev server on https://localhost:3000.
bun run dev:outlookThen sideload manifest.xml in Outlook for local development. The
steps depend on the host:
- Outlook on the web: open Settings, go to the add-ins page,
choose "Add a custom add-in" then "Add from file", and pick
manifest.xml. - New Outlook on Windows: use the same add-ins management page, reached from Outlook on the web with the same account.
After sideloading, open a new message, fill in a recipient, and press Send. Outlook's Smart Alerts dialog should appear. Choose "Open review", check the required items in the task pane, then press Send again without changing the draft.
You can test the review flow in a browser without Outlook:
bun install
bun run dev:emulatorOr start the normal dev server and open /emulator.html on the URL
Vite prints. If port 3000 is busy, Vite will choose the next free
port, for example https://localhost:3001/emulator.html. The
emulator uses the same domain logic and dialog renderer as the
Outlook send handler, but it does not load Office.js or call Outlook
APIs. Edit the draft fields, switch scenarios, then click "Review
send" to rebuild the dialog.
For Outlook sideloading, use bun run dev:outlook. The manifest is
fixed to https://localhost:3000, so that script intentionally fails
if port 3000 is already in use.
bun run checkThis runs, in order: lint (oxlint) and format check (oxfmt), type check on both tsconfigs, tests with coverage, the production build, and manifest validation. Each step must pass. Useful single steps:
bun run typecheck # tsc on src and on the build config
bun run lint # oxlint
bun run format # oxfmt --write
bun run test # vitest, run once
bun run test:coverage # vitest with coverage on the pure layers
bun run build # tsc --noEmit then vite build
bun run validate # office-addin-manifest validateThe Marketplace release loads the hosted add-in from Cloudflare
Pages. The repository includes wrangler.toml, so Pages can build
with bun run build and publish dist/. During that build,
scripts/generate-manifest.js writes dist/manifest.xml with
https://avishaikofun.com embedded.
The add-in runtime is served from the apex,
avishaikofun.com, and that host belongs
to this repository. The company site is not here: it lives in
hjosugi/avishaikofun-site
and is served from www, so a copy edit to a marketing page no longer
goes through this project's build, tests, and release gates. The apex
root redirects there (public/_redirects); every other path is the
add-in.
The Mail Lookout product pages — support.html, privacy.html,
terms.html — stayed behind on purpose. The manifest hard-codes
SupportUrl and the Marketplace listing points at those URLs, so
moving them would mean re-certification.
End users should install from the
Microsoft Marketplace listing;
the hosted /manifest.xml remains available for development and
testing.
Tagged releases also attach mail-lookout-manifest.xml on the
GitHub Releases page. Use that file when you want a fixed version
instead of the latest hosted manifest.
To bump the patch version, commit it, push the branch, and push the release tag for GitHub Releases:
bun run version:patchUse bun run version:minor, bun run version:major, or bun run version:set 1.2.3 for other version changes. These commands update
package.json and manifest.xml, create the
version commit, push the current branch, then create and push the
v* release tag. GitHub Actions creates the release asset from that
tag. The script shows the next version first and asks for a y/N
confirmation before changing files. Use bun run version:bump patch
when you only want the local version commit without pushing or tagging.
See CLOUDFLARE.md for the step-by-step flow.
The source manifest still ships with placeholder values. Replace them before a production or marketplace release.
- GUID. Replace the
<Id>inmanifest.xmlwith your own GUID. - URLs. Cloudflare Pages is configured for
https://avishaikofun.com. For another host, replace everyhttps://localhost:3000inmanifest.xmlwith your host or runADDIN_HOST_URL=https://your-domain.example bun run build. Serve thedist/folder over HTTPS at that host. The entry JS keeps a stable name (/assets/commands.js), so the manifest URLs do not change between builds. - Internal domains. Edit
internalDomainsinsrc/config/defaults.ts. The shipped default isavishaikofun.com. If this list is wrong, every recipient looks external. - Metadata. Replace
ProviderName,SupportUrl, andAppDomainsinmanifest.xml.
Then publish through the Microsoft 365 admin center for your organization, or sideload for a single user.
Mail Lookout is publicly available from Microsoft Marketplace. For future Marketplace updates, deploy and verify the hosted build, bump the manifest version, and submit the updated package through Partner Center.
For the Marketplace description and certification notes, see
docs/marketplace-resubmission.md.
The shipped defaults live in
src/config/defaults.ts — fork that file
to change them. At runtime, the Settings task pane overrides a subset
per user, marked below. The main options:
internalDomains: domains treated as internal (also editable in the Settings pane).sendDelaySeconds: the default countdown before a confirmed message is sent (also editable in the Settings pane).requireRecipientConfirmation: include recipients in the send-time confirmation (also editable in the Settings pane).requireAttachmentConfirmation: include attachments in the send-time confirmation (also editable in the Settings pane).requireBodyConfirmation: include the body preview in the send-time confirmation (also editable in the Settings pane).allowSendAnyway: offer Outlook's Send Anyway on a blocked send (also editable in the Settings pane). Off by default; see SendMode for what it can and cannot reach.attachmentKeywords: words that hint the body refers to an attachment, used by the forgotten-attachment warning.warnOnEmptySubject: warn when the subject is blank.fallbackLocale: language used when the host language is unknown.dialog: dialog width and height as a percent of the screen.
The messages are type-safe. To add a language:
- Copy
src/i18n/locales/en.tsto a new file, for examplede.ts, and translate every value. - Add one line to
src/i18n/catalog.ts: import it and add it to thelocalesobject.
The compiler will tell you if you miss a key. A test in
test/i18n.test.ts also checks that every locale has the same set
of keys. Nothing else needs to change. The locale tag type updates
itself from the keys of locales.
The manifest uses SendMode="SoftBlock". When the add-in cancels a
send, the user must go back and edit the draft. By default there is no
one-click "send anyway" path. This is on purpose: a confirmation tool
whose every cancel is one click to bypass does not confirm much.
The first send attempt shows the Smart Alerts dialog and cancels the send. The dialog's action button opens a task pane with the checkbox review UI. After the task pane marks the draft as reviewed, it sends the message through Outlook's compose API. If any unexpected error happens, the handler cancels the send. It never sends real mail without confirmation.
SendMode also decides the case the add-in cannot decide itself: what
happens when the runtime never loads, because the host is unreachable
or a browser extension blocked the frame. Under SoftBlock Outlook
sends the message — no dialog, no warning, nothing in a log. The
add-in is silently absent rather than visibly broken.
Block is the only mode that refuses the send there, and it is not
available to us. AppSource rejects the manifest:
Error #1: Block SendMode is not allowed
PromptUser does not help either — it also sends when the add-in is
unavailable, and it would additionally put a permanent bypass button on
every cancel. So for a Marketplace-distributed add-in this gap cannot
be closed, only monitored: scripts/heartbeat.js checks the host every
six hours. Closing it requires distributing the manifest yourself, by
sideloading or admin deployment, with SendMode="Block".
Settings → When a send is blocked → Offer Send Anyway adds a Send Anyway button to a canceled send. It is off by default.
The direction is forced by the API, not chosen. sendModeOverride
accepts exactly one value, promptUser, so a running handler can
loosen the mode the manifest declares but can never tighten it. Strict
therefore has to be what ships in the manifest, with this as the
opt-out — shipping PromptUser and letting a setting harden it is not
expressible.
The same asymmetry sets the limit, and the Settings pane says so next to the checkbox: the setting only applies when the add-in actually ran. It cannot change the failed-to-load case above, in either direction.
Be honest about what this is and is not.
- Custom Office dialogs can't be opened from the send event.
OnMessageSendruns through event-based activation, and Office UI APIs such asOffice.context.ui.displayDialogAsyncare blocked there. The production send flow therefore uses the built-in Smart Alerts dialog instead of the browser preview dialog. - The send delay runs in the review pane. Outlook's Smart Alerts handler must stay short-running, so the task pane owns the countdown and then calls Outlook's compose send API. Closing or refreshing the pane cancels that pending send.
- Scheduled send / Send later is intentionally bypassed. Mail
Lookout checks
delayDeliveryTimeat send time. If a future delivery time is set, the add-in allows the event immediately and doesn't open the review pane. This avoids converting a scheduled message into an immediatesendAsyncsend, but it also means Mail Lookout does not protect scheduled messages. - Classic Outlook on Windows is not a target. That host uses a JavaScript-only runtime for send handlers. This project builds an ES module that loads through an HTML page in a browser runtime, which is what new Outlook and Outlook on the web use. The manifest declares a JS-only override for schema reasons, but the classic path is not supported or tested.
- Outlook mobile is not supported. Smart Alerts on send do not run there.
- If the add-in cannot load, the message sends unchecked. Outlook
loads
commands.htmlfrom the host on every send. If that fails — host down, extension blocking the frame —SoftBlocklets the send through with no dialog and no warning, and no setting can change it, because none of our code runs. OnlySendMode="Block"refuses there, and AppSource does not allow Block for a Marketplace add-in. This is the add-in's real failure mode;scripts/heartbeat.jswatches the host every six hours to keep it rare. See SendMode.
Use this add-in at your own risk. The authors and contributors are not responsible for any damages, losses, misdelivery, business interruption, or other liability arising from the use of, inability to use, deployment of, or modification of this software. Review the configuration and behavior before using it in a production environment.
OutlookOkan is an existing send-confirmation tool for Outlook. Mail Lookout respects the work and the problem it addresses.
Mail Lookout is an independent project. It is not affiliated with, endorsed by, or sponsored by OutlookOkan or its author.
This project ships an add-in only manifest (manifest.xml), which
is well supported on Outlook on the web and new Outlook today. The
unified manifest for Microsoft 365 is the newer format and is the
direction Microsoft is moving. If you need it, the
office-addin-manifest tool can convert an XML manifest to the
unified format. The runtime code in this project does not change;
only the manifest does.
0BSD. You can use, copy, modify, and distribute this project for almost any purpose.



