The source for fluentsmtp.com/docs — user documentation for the
FluentSMTP WordPress plugin by WPManageNinja.
Built with VitePress 1.x.
git clone <repo-url>
cd fluentsmtp-user-docs
npm install
npm run dev # http://localhost:5173| Command | What it does |
|---|---|
npm run dev |
Local dev server with hot reload |
npm run build |
Static build into .vitepress/dist/ |
npm run preview |
Serve the built output locally |
node .claude/skills/validate-docs/scripts/validate.mjs |
Structural check — run before committing |
Image work additionally needs cwebp:
brew install webp24 articles across six categories, plus a homepage, changelog, and support page.
| Category | Covers |
|---|---|
| Getting Started | Installation, dashboard tour, global settings, provider overview |
| Delivery Connections | Gmail, Outlook / Office 365, Amazon SES, Brevo, Mailgun, SendGrid, SparkPost, Postmark, Elastic Email, Netcore, SMTP2GO, and generic host SMTP |
| Obtain SMTP Credentials | Pulling credentials from hosting control panels (cPanel) |
| Alerts | Email summaries and failure notifications via Slack, Telegram, Discord |
| Advanced Functionalities | Multiple connections and automatic routing |
| Miscellaneous | Email logs |
.vitepress/
config.js # sidebar, nav, URL rewrites, branding
theme/ # default theme + a per-page feedback widget
docs/ # srcDir — all content
index.md # homepage
changelog.md
support.md
{category}/{slug}.md # articles
public/images/ # all screenshots, WebP only
.claude/skills/ # authoring skills for Claude Code
CLAUDE.md # conventions + writing style guide
Category folders are stripped from the public URL by rewrites in .vitepress/config.js, and cleanUrls: true drops .html:
docs/delivery-connections/configure-mailgun-with-fluentsmtp.md
↓
https://fluentsmtp.com/docs/configure-mailgun-with-fluentsmtp
Three things follow from this, and they cause most mistakes:
- Slugs must be globally unique. Two files with the same name in different categories collide on the same URL.
- Internal links use the bare slug —
[text](/install-and-activate-fluentsmtp), not the folder path. - Renaming a file changes its public URL and breaks inbound links. Rename with the
/rename-docskill, which fixes the sidebar, image folder, and links together.
Each category needs its own rewrite line in config.js. The sidebar is maintained by hand — nothing is auto-generated, so a new doc is invisible in navigation until it is added there.
Manually:
- Create
docs/{category}/{slug}.md - Add a sidebar entry in
.vitepress/config.jsunder the matching section - Put screenshots in
docs/public/images/{category}/{slug}/as WebP - Run the validator
With Claude Code, the repo ships skills that do this and keep the invariants intact:
| Skill | Purpose |
|---|---|
/add-doc {slug} {category} |
Scaffold an article and register it in the sidebar |
/add-category {slug} {Name} |
New section: folder, rewrite rule, sidebar block |
/update-doc {slug} |
Edit a doc without disturbing its established voice |
/rename-doc {old} {new} |
Re-slug or move, fixing links, images, and sidebar |
/sync-images [{slug}] |
Download remote images, convert to WebP, remap links |
/validate-docs |
Check links, images, sidebar, slugs, and rewrites |
/style-check [{slug}] |
Audit prose against the writing style guide |
Images — WebP only, stored at docs/public/images/{category}/{slug}/ and referenced as /images/{category}/{slug}/file.webp (the public/ segment is dropped; it is the web root). External image URLs are never linked. Alt text is required on every image.
Writing — Docs follow a specific house voice: imperative and action-first, sequential connectors (First, → Now, → Then, → Finally,), bolded UI element names, Title Case headers, and blockquote notes rather than alarm-word warnings. The full guide, with the intro-paragraph patterns and the Prerequisites block every setup guide carries, is in CLAUDE.md.
Validation — validate.mjs checks structure: duplicate slugs, docs missing from the sidebar, dead nav links, broken internal links, missing or non-WebP images, empty alt text, missing rewrite rules, and orphaned assets. It exits non-zero on errors.
node .claude/skills/validate-docs/scripts/validate.mjs # full report
node .claude/skills/validate-docs/scripts/validate.mjs --quiet # errors only
node .claude/skills/validate-docs/scripts/validate.mjs --json # machine-readableVideos are embedded the standard VitePress way — a plain YouTube <iframe> written directly in the markdown — inside a .video-container wrapper:
<div class="video-container">
<iframe
src="https://www.youtube.com/embed/hDcolf4oLlM"
title="Connect Gmail or Google Workspace Emails With FluentSMTP"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen
></iframe>
</div>The wrapper is required: VitePress applies max-width: 100% to img and video but not to iframe, so an unwrapped embed keeps its intrinsic 560x315 and overflows on mobile. The wrapper makes the frame fluid at width: 100% with a 16:9 aspect-ratio, giving it exactly the rendered width of a screenshot at every breakpoint. Styles are in .vitepress/theme/custom.css.
Only videos from the official WPManageNinja channel are embedded. Two of the 24 docs currently have one, which is all the official channel offers. See CLAUDE.md for the full convention.
Every doc page renders a thumbs-up/down and comment widget below the content, implemented in .vitepress/theme/components/Feedback.vue. Responses POST to a Google Apps Script endpoint and are tagged with PRODUCT_NAME, which distinguishes this repo from its sibling WPManageNinja doc sites. Change that constant if you reuse the component elsewhere.
npm run build # → .vitepress/dist/
npm run preview.vitepress/dist/ is the deployable artifact. There is no CI pipeline in this repository — builds and deploys are handled externally.
Note: the live site is served under
/docs/, butconfig.jssets nobase. If assets 404 after deploying to a subpath, check how the host serves the build before adding one — an incorrectbasebreaks every asset path.
Documentation content © WPManageNinja. See the FluentSMTP plugin for plugin licensing.
Every page has its own link-preview card — the image Slack, X, LinkedIn and Facebook show when a docs URL is shared. Cards are generated, not designed by hand: scripts/generate-featured-images.mjs renders a branded 1200×630 PNG carrying the page's title and section into docs/public/images/featured/, and the VitePress config (featuredImageFor()) points each page's og:image / twitter:image at it. A page with no card falls back to default.png.
npm run featured:generate # render cards for pages that don't have one yet (idempotent)
npm run featured:regenerate # re-render every card (after changing the generator's design)- Run
npm run featured:generateafter adding a page and commit the PNG alongside it. - If you rename or retitle a page, delete its old card first and run the generator again — it skips existing files and only reports orphans, it never deletes them.
- Card naming rule: the page's served path (after
rewrites) minus.md, with/replaced by--, plus.png. It lives in both the script (cardNameFor()) and the config (featuredImageFor()) — change one, change the other.
