docs(web/guides): fix sending-email mailer pattern, attachment paths, and SMTP defaults wording - #3093
Conversation
…paths, and SMTP wording Behavioral audit (P1 batch 2, p1-7-email) corrections to digging-deeper/sending-email.mdx: - Mailer pattern: replace new wheels.Controller().sendEmail(...) — throws on every engine (no variables.params) — with the verified controller(name, params) factory form; add a caution citing #3078. - Attachments: examples used slash-containing paths that skip filePath resolution; switch to bare filenames, document the separator rule and that filePath expands relative to the web root (public/files/). - sendEmail defaults: from/to/subject are engine-required parameters, so configured defaults for them never apply; drop from= from both set(functionName="sendEmail", ...) examples and document why. - Background-job rationale: cfmail spools by default, so the request does not normally wait for the SMTP handoff; reword the latency claim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
There was a problem hiding this comment.
Wheels Bot — Reviewer
TL;DR: This docs-only PR fixes four behavioral inaccuracies in the v4 digging-deeper/sending-email.mdx guide (broken mailer-CFC pattern, contradictory attachment examples, never-honored from default, overstated SMTP latency claim). I verified every technical claim in the diff against the framework source and all of them are accurate. Verdict: comment — no blocking findings, one minor non-blocking observation below.
Verification of the diff's claims (all confirmed)
| Claim in diff | Framework evidence |
|---|---|
from/to/subject are engine-required, so configured defaults for them never apply |
vendor/wheels/controller/miscellaneous.cfc:22-24 — required string from, required string to, required string subject; the engine enforces these before $args() (line 32) runs |
new wheels.Controller().sendEmail(...) throws because the rendering pipeline dereferences variables.params even for absolute template paths |
vendor/wheels/controller/rendering.cfc:577 — $generateIncludeTemplatePath declares the default argument $controllerName = variables.params.controller, evaluated regardless of whether $name is absolute |
controller(name, params) factory builds a request-capable instance, and works without a Mailer.cfc existing |
vendor/wheels/Global.cfc:1209 (factory; instantiates via $createControllerObject(params) when params is non-empty) and Global.cfc:1135 (falls back to the base Controller when no controller file is found on any path). Same pattern used throughout vendor/wheels/tests/specs/controller/initializationSpec.cfc |
Paths without a separator resolve against filePath; paths with a separator pass through to cfmailparam unchanged |
vendor/wheels/controller/miscellaneous.cfc:152 — if (!ReFindNoCase("\|/", local.item)) prepends ExpandPath($get("filePath")) & "/", else no transformation |
filePath default is files, expanding under the web root (public/files/ in the v4 template) |
vendor/wheels/events/init/views.cfm:13 — application.$wheels.filePath = "files"; and public/files/ exists in the repo's app template |
The reworded SMTP-spooling paragraph matches standard cfmail behavior on both Lucee and Adobe (spool-by-default), and the push-to-a-job advice is correctly preserved.
Docs
- Minor, non-blocking: the guide's new centerpiece is the
controller()factory, but its API docstring says "Used primarily for testing purposes" (vendor/wheels/Global.cfc:1201). A reader cross-referencing the API reference may hesitate at recommending a "testing" helper for production mailers. Since #3078 (cited in the new Aside) tracks the proper out-of-requestsendEmail()hardening, consider either softening that docstring in a follow-up or adding half a sentence in the guide noting this is the supported interim pattern until #3078 lands. No change required to merge.
Commits
docs(web/guides): fix sending-email guide mailer pattern, attachment paths, and SMTP wording — valid type, header 94 chars, DCO sign-off present and matching the author. PR title is also a valid conventional-commit header (96 chars). No findings.
Tests
Docs-only change; the PR retains the {test:compile} annotations on every modified code block and reports pnpm verify:docs passing 11/11 on the page. No framework spec needed. No changelog fragment needed (docs type, not a user-facing fix/feat).
Summary
Guide-behavioral-audit P1 batch 2 (work item
p1-7-email) corrections todigging-deeper/sending-email.mdx. Each fix documents current behavior verified live on Lucee 7 and/or Adobe 2023; the one broken-but-unfixed framework gap is cited as an issue, not papered over.Corrections
Mailer-CFC pattern rewritten to a working form (claim
email-08-mailer-cfc-pattern, docs-wrong; verified on Lucee 7 + Adobe 2023). The page's centerpiecenew wheels.Controller().sendEmail(...)pattern throws HTTP 500 on every engine — a bare controller instance has novariables.params, and$renderView→$generateIncludeTemplatePath(rendering.cfc:575) dereferences it even for absolutetemplate=paths (Lucee: "has no accessible Member with name [PARAMS]"; Adobe: "Element PARAMS is undefined"). BothUserMailermethods now use the verifiednew wheels.Global().controller(name=..., params=...)factory (returned struct had correct subject/to/body on both engines), with a caution Aside explaining the failure and citing sending-email guide's mailer patternnew wheels.Controller().sendEmail()throws on every engine (no variables.params) — fix docs and/or harden $renderView for out-of-request senders #3078 for the optional out-of-requestsendEmail()hardening.Attachment examples no longer contradict the resolution rule (claim
email-21-guide-examples-contain-slashes-DOC-BUG, docs-wrong; verified Lucee 7). The prose said "paths without a slash resolve relative tofilePath," but both examples usedinvoices/...paths — which the slash check (miscellaneous.cfc:152) passes through tocfmailparamunchanged, resolving against the JVM working directory at delivery time. Examples switched to bare filenames; prose tightened to "without any directory separator (/or\)" and now explains the pass-through behavior plus anExpandPath()escape hatch. Also fixes theemail-20nit:filePathdefaultfilesexpands relative to the web root (public/files/in the v4 template), not "files/ at the app root."fromremoved from thesendEmaildefaults examples (claimemail-26-from-default-vs-required-signature, docs-wrong; verified Lucee 7 + Adobe 2023).from/to/subjectarerequiredparameters (miscellaneous.cfc:22-24), so the engine throws a missing-parameter error before$argscan apply a configured default — afromdefault is never honored. Droppedfrom=from theconfig/settings.cfmandconfig/production/settings.cfmset(functionName="sendEmail", ...)blocks and added a paragraph documenting why those three can't be defaulted.SMTP-blocking wording corrected (claim
email-11-synchronous-blocks-on-smtpevidence). "the user's browser waits for SMTP to hand off the message" overstated the default:cfmailspools to disk by default on Lucee and Adobe, so the request normally pays render + compose + spool, not the SMTP handoff. Reworded; the push-to-a-job advice stands.Verification
pnpm verify:docs src/content/docs/v4-0-0/digging-deeper/sending-email.mdx→ 11 tagged blocks, 11 passed, exit 0.Refs #3078
🤖 Generated with Claude Code